diff --git a/kitsune/audio_codec_pps_driver.h b/kitsune/audio_codec_pps_driver.h index a72935d5..861742ca 100644 --- a/kitsune/audio_codec_pps_driver.h +++ b/kitsune/audio_codec_pps_driver.h @@ -149,36 +149,10 @@ static const reg_value REG_Section_program[] = { { 3,0x00}, // # reg[0][1][4 ] = 0x00 ; reg(0)(1)(0x04 => 4 ) RDAC FIR { 4,0x00}, -#if 0 -// # reg[0][1][31] = 0x80 ; reg(0)(1)(0x1F =>31 ) HP in ground Centered mode; HPL gain 0 dB - { 31,0x80}, -// # reg[0][1][32] = 0x00 ; reg(0)(1)(0x20 =>32 ) HPR independent gain 0 dB - { 32,0x00}, -// # reg[0][1][33] = 0x28 ; reg(0)(1)(0x21 =>33 ) Charge pump runs on Osc./4 - { 33,0x28}, -// # reg[0][1][34] = 0x33 ;0x3e ; reg(0)(1)(0x22 =>34 ) Set CP mode - { 34,0x33}, -// # reg[0][1][35] = 0x10 ; reg(0)(1)(0x23 =>35 ) Power up CP with HP - { 35,0x10}, -// # reg[0][1][52] = 0x40 ; reg(0)(1)(0x34 => 52) ADC IN1_L is selected for left P - { 52,0x40}, -// # reg[0][1][54] = 0x40 ; reg(0)(1)(0x36 => 54) ADC CM1 is selected for left M - { 54,0x40}, -// # reg[0][1][55] = 0x40 ; reg(0)(1)(0x37 => 55) ADC IN1_R is selected for right P - { 55,0x40}, -// # reg[0][1][57] = 0x40 ; reg(0)(1)(0x39 => 57) ADC CM1 is selected for right M - { 57,0x40}, - -#endif // # reg[0][1][121] = 0x33 ; reg(0)(1)(0x79 => 121) Quick charge time for Mic inputs {121,0x33}, // # reg[0][1][122] = 0x01 ; reg(0)(1)(0x7A => 122) Vref charge time - 40 ms. {122,0x01}, -#if (KITSUNE_CODE==1) -#if 0 - { 51, (4<<0)}, -#endif -#endif }; static const reg_value REG_Section_program2[] = { @@ -227,13 +201,6 @@ static const reg_value REG_Section_program2[] = { { 63,0xC2}, // # reg[0][0][64] = 0x00 ; reg(0)(0)(0x40 => 64) DAC Left and Right DAC unmuted with indep. vol. ctrl { 64,0x00}, -#if (KITSUNE_CODE==1) -#if 0 - // digital volume control - { 65, 0x30}, - { 66, 0x30}, -#endif -#endif // # reg[0][0][81] = 0xd6 ; reg(0)(0)(0x51 => d6) ADC Powerup ADC left and right channels in Digital mode(soft-stepping disable) { 81,0xD6}, // # reg[0][0][82] = 0x00 ; reg(0)(0)(0x51 => 81) ADC Powerup ADC left and right channels (soft-stepping disable); reg(0)(0)(0x52 => 82) ADC Unmute ADC left and right channels,L,R fine gain=0dB @@ -246,8 +213,6 @@ static const reg_value REG_Section_program2[] = { { 45,0x06}, // # reg[0][1][46] = 0x0C ; -6db { 46,0x0C}, -// # reg[0][1][47] = 0x0C ; - { 47,0x0C}, #if (MUTE_SPK==1) // # reg[0][1][48] = 0x21 ; 12db { 48,0x00}, @@ -358,38 +323,6 @@ static const reg_value REG_Section_program2[] = { // # reg[0][0][82] = 0 { 82,0x00}, -#if 0 // AGC -// # reg[0][0][86] = 32 - { 86,0x20}, -// # reg[0][0][87] = 254 - { 87,0xFE}, -// # reg[0][0][88] = 0 - { 88,0x00}, -// # reg[0][0][89] = 104 - { 89,0x68}, -// # reg[0][0][90] = 168 - { 90,0xA8}, -// # reg[0][0][91] = 6 - { 91,0x06}, -// # reg[0][0][92] = 0 - { 92,0x00}, -// # reg[0][0][84] = 0 - { 84,0x00}, -// # reg[0][0][94] = 32 - { 94,0x20}, -// # reg[0][0][95] = 254 - { 95,0xFE}, -// # reg[0][0][96] = 0 - { 96,0x00}, -// # reg[0][0][97] = 104 - { 97,0x68}, -// # reg[0][0][98] = 168 - { 98,0xA8}, -// # reg[0][0][99] = 6 - { 99,0x06}, -// # reg[0][0][100] = 0 - {100,0x00}, -#endif }; const static reg_value miniDSP_A_reg_values[] = { diff --git a/kitsune/audio_types.h b/kitsune/audio_types.h index c8299c7b..bd3a1db6 100644 --- a/kitsune/audio_types.h +++ b/kitsune/audio_types.h @@ -13,17 +13,9 @@ #define MIN_CLASSIFICATION_ENERGY (100) -#define AUDIO_FFT_SIZE_2N (8) -#define AUDIO_FFT_SIZE (1 << AUDIO_FFT_SIZE_2N) -#define EXPECTED_AUDIO_SAMPLE_RATE_HZ (AUDIO_SAMPLE_RATE) - -#define SAMPLE_RATE_IN_HZ (EXPECTED_AUDIO_SAMPLE_RATE_HZ / AUDIO_FFT_SIZE) +#define SAMPLE_RATE_IN_HZ (66) #define SAMPLE_PERIOD_IN_MILLISECONDS (1000 / SAMPLE_RATE_IN_HZ) -#define NUM_AUDIO_FEATURES (16) - -#define OCTOGRAM_SIZE (AUDIO_FFT_SIZE_2N - 1) - /* // use simplelink.h instead #define TRUE (1) @@ -37,39 +29,13 @@ extern "C" { #endif -typedef struct { - uint16_t psd_min_energy; - -} AudioFeaturesOptions_t; - -typedef struct { - uint16_t min_energy_classification; -} AudioClassifierOptions_t; - -typedef enum { - segmentCoherent -} ESegmentType_t; - -typedef struct { - int64_t t1; - int64_t t2; - int32_t duration; - ESegmentType_t type; - -} Segment_t; typedef struct { - int64_t samplecount; + int64_t samplecount; int16_t logenergy; - int8_t feats4bit[NUM_AUDIO_FEATURES]; } AudioFeatures_t; -/* FOR SAVING AUDIO / UPLOADING AUDIO - * - * Yes, some of these flags are mutually exclusive. Others aren ot. - */ - #define AUDIO_TRANSFER_FLAG_AUTO_CLOSE_OUTPUT (1 << 0) /* automatically close output stream when done */ @@ -89,21 +55,18 @@ typedef struct { uint32_t unix_time; } DeviceCurrentInfo_t; -typedef struct { - int32_t logenergy[OCTOGRAM_SIZE]; -} OctogramResult_t; typedef struct { int32_t num_disturbances; int32_t num_samples; int32_t peak_energy; int32_t peak_background_energy; + int32_t disturbance_time_count; uint8_t isValid; -} AudioOncePerMinuteData_t; +} AudioEnergyStats_t; -typedef void (*SegmentAndFeatureCallback_t)(const int16_t * feats, const Segment_t * pSegment); typedef void (*AudioFeatureCallback_t)(const AudioFeatures_t * pfeats); -typedef void (*AudioOncePerMinuteDataCallback_t) (const AudioOncePerMinuteData_t * pdata); +typedef void (*AudioEnergyStatsCallback_t) (const AudioEnergyStats_t * pdata); typedef void (*NotificationCallback_t)(void * context); typedef void (*RecordAudioCallback_t)(const AudioCaptureDesc_t * request); diff --git a/kitsune/audioclassifier.c b/kitsune/audioclassifier.c deleted file mode 100644 index d8ff0c3a..00000000 --- a/kitsune/audioclassifier.c +++ /dev/null @@ -1,438 +0,0 @@ - -#include "audioclassifier.h" -#include "fft.h" -#include "debugutils/debuglog.h" -#include "debugutils/matmessageutils.h" -#include "hellomath.h" -#include "machinelearning/audiohmm.h" -#include -#include -//#include "uartstdio.h" - -#define CIRCULAR_FEATBUF_SIZE_2N (5) -#define CIRCULAR_BUF_SIZE (1 << CIRCULAR_FEATBUF_SIZE_2N) -#define CIRCULAR_BUF_MASK (CIRCULAR_BUF_SIZE - 1) -#define BUF_SIZE_IN_CHUNK (32) - -#define CLASSIFIER_BUF_LEN (16) -#define MAX_NUMBER_CLASSES (5) -#define EXPECTED_NUMBER_OF_CLASSIFIER_INPUTS (NUM_AUDIO_FEATURES) - -#define CLASS_OF_INTEREST_TO_ENABLE_CALLBACK (0) - -#define RECORD_DURATION_IN_MS (10000) -#define RECORD_DURATION_IN_FRAMES (RECORD_DURATION_IN_MS / SAMPLE_PERIOD_IN_MILLISECONDS) - -#define SNORING_LOG_LIK_THRESHOLD_Q10 (600) - - -#ifndef true -#define true (1) -#endif - -#ifndef false -#define false (0) -#endif - - - - -typedef struct { - uint8_t packedbuf[BUF_SIZE_IN_CHUNK][NUM_AUDIO_FEATURES/2];// 32 x 16 = 2^5 * 2^4 = 2^9 = 256 bytes - int16_t energy[BUF_SIZE_IN_CHUNK]; //32 * 2 = 64bytes - int64_t samplecount; // 8 bytes - int16_t maxenergy; // 2 bytes -} AudioFeatureChunk_t; //330 bytes - -typedef struct { - int8_t classifier_feat_buf[CLASSIFIER_BUF_LEN][NUM_AUDIO_FEATURES]; - uint16_t classifier_feat_idx; - - //cicular buffer of incoming data - uint8_t packedbuf[CIRCULAR_BUF_SIZE][NUM_AUDIO_FEATURES/2]; //32 * 8 = 256 bytes - int16_t totalenergy[CIRCULAR_BUF_SIZE];// - - uint16_t chunkbufidx; //current index of chunk to write to, wraps to zero when it >= chunk_buf_size - uint16_t numchunkbuf; //number of chunks written, saturated at chunk_buf_size - - AudioFeatureChunk_t * pchunkbuf; - uint32_t chunk_buf_size; - - - uint16_t incomingidx; - uint16_t numincoming; - - uint8_t isThereAnythingInteresting; - uint8_t isWorthClassifying; - - -} DataBuffer_t; - -typedef struct { - const DataBuffer_t * buf; - uint32_t currentidx; - uint32_t endidx; - uint8_t state; - int8_t unpackedbuffer[BUF_SIZE_IN_CHUNK][NUM_AUDIO_FEATURES]; //32 * 16 * 1 = 512 bytes - -} Encoder_t; - -static const char * k_id_feature_chunk = "feature_chunk"; -static const char * k_id_energy_chunk = "energy_chunk"; - -//"long term storage" -static DataBuffer_t _buffer; -static Classifier_t _classifier; -static Classifier_t _hmm; - - -static inline uint8_t pack_int8_to_int4(const int8_t x) { - const uint8_t sign = x < 0; - - return (x & 0x07) | (sign * 8); -} - -// assumes two's complement architecture (who the heck doesn't do this these days?) -static inline void unpack_int4_pair_to_int8(const uint8_t packed, int8_t * upper, int8_t * lower) { - *lower = packed & 0x07; - if (packed & 0x08) { - *lower |= 0xF8; //sign extension - } - - *upper = (packed & 0x70) >> 4; - if (packed & 0x80) { - *upper |= 0xF8; //sign extension - } - - -} - -static void PackFeats(uint8_t * datahead, const int8_t * feats4bit) { - uint8_t i; - uint8_t idx; - - - for (i = 0; i < NUM_AUDIO_FEATURES/2; i++) { - idx = 2*i; - - datahead[i] = pack_int8_to_int4(feats4bit[idx]); - datahead[i] |= (pack_int8_to_int4(feats4bit[idx + 1]) << 4); - } -} - - - -static void UnpackFeats8(int8_t * unpacked8, const uint8_t * datahead) { - uint8_t i; - for (i = 0; i < NUM_AUDIO_FEATURES/2; i++) { - //lsb first - - unpack_int4_pair_to_int8(datahead[i],unpacked8+1,unpacked8); - unpacked8 += 2; - } -} - -#if 0 -static void TestPackUnpack(void) { - int8_t input[NUM_AUDIO_FEATURES] = {-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7}; - int8_t out[NUM_AUDIO_FEATURES] = {0}; - uint8_t packed[NUM_AUDIO_FEATURES/2]; - int foo = 3; - PackFeats(packed, input); - UnpackFeats8(out, packed); - - foo++; - -} -#endif - -static void CopyCircularBufferToPermanentStorage(int64_t samplecount) { - - AudioFeatureChunk_t chunk; - uint16_t idx; - int32_t size1,size2; - uint16_t i; - int16_t max; - - idx = _buffer.incomingidx; //oldest - /* - t2 t1 - ---| |------- - - t1 t2 - |-------------| - */ - - //copy circular buf out in chronological order - size1 = CIRCULAR_BUF_SIZE - idx; - memcpy(&chunk.packedbuf[0][0],&_buffer.packedbuf[idx][0],size1*NUM_AUDIO_FEATURES/2*sizeof(uint8_t)); - memcpy(&chunk.energy[0],&_buffer.totalenergy[idx],size1*sizeof(int16_t)); - - if (size1 < CIRCULAR_BUF_SIZE) { - size2 = idx; - memcpy(&chunk.packedbuf[size1][0],&_buffer.packedbuf[0][0],size2*NUM_AUDIO_FEATURES/2*sizeof(uint8_t)); - memcpy(&chunk.energy[size1],&_buffer.totalenergy[0],size2*sizeof(int16_t)); - } - - /* find max in energy buffer */ - max = MIN_INT_16; - for (i = 0 ; i < CIRCULAR_BUF_SIZE; i++) { - if (_buffer.totalenergy[i] > max) { - max = _buffer.totalenergy[i]; - } - } - chunk.maxenergy = max; - chunk.samplecount = samplecount; - - - memcpy(&_buffer.pchunkbuf[_buffer.chunkbufidx],&chunk,sizeof(chunk)); - _buffer.chunkbufidx++; - - //wrap - if (_buffer.chunkbufidx >= _buffer.chunk_buf_size) { - _buffer.chunkbufidx -= _buffer.chunk_buf_size; - } - - //track how full the buffer is even if you wrapped - //if you wrapped, you're discarding data, but you're still full - if (_buffer.numchunkbuf < _buffer.chunk_buf_size) { - _buffer.numchunkbuf++; - } - -} - - - -void AudioClassifier_SetStorageBuffers(void * buffer, uint32_t buf_size_in_bytes) { - memset(&_buffer,0,sizeof(_buffer)); - - _buffer.pchunkbuf = (AudioFeatureChunk_t *)buffer; - _buffer.chunk_buf_size = buf_size_in_bytes / sizeof(AudioFeatureChunk_t); - -} - -void AudioClassifier_Init(RecordAudioCallback_t recordfunc) { - memset(&_buffer,0,sizeof(_buffer)); - memset(&_classifier,0,sizeof(Classifier_t)); - memset(&_hmm,0,sizeof(_hmm)); - -} - - -void AudioClassifier_DataCallback( AudioFeatures_t * pfeats) { - - uint16_t idx; - - - - /* - - Data comes in, and we save it to a circular buffer. - Classification is disabled for now - - */ - - /************************ - THE BUFFERING SECTION - ***********************/ - - //do nothing if we do not have a storage buffer allocated - if (!_buffer.pchunkbuf || _buffer.chunk_buf_size == 0) { - return; - } - - idx = _buffer.incomingidx; - PackFeats(_buffer.packedbuf[idx],pfeats->feats4bit); - - _buffer.totalenergy[idx] = pfeats->logenergy; - - //increment circular buffer index - _buffer.incomingidx++; - _buffer.incomingidx &= CIRCULAR_BUF_MASK; - - //increment until full - if (_buffer.numincoming < CIRCULAR_BUF_SIZE) { - _buffer.numincoming++; - } - - //everything is interesting - _buffer.isThereAnythingInteresting = true; - _buffer.isWorthClassifying = false; //don't classify anything for now - - - //if something interesting happend and the circular buffer is full - //dump it to storage - // if (_buffer.isThereAnythingInteresting == true && - if( _buffer.numincoming == CIRCULAR_BUF_SIZE ) - { - //this may block... hopefully not for too long? - CopyCircularBufferToPermanentStorage(pfeats->samplecount); - _buffer.numincoming = 0; //"empty" the buffer - _buffer.incomingidx = 0; - _buffer.isThereAnythingInteresting = false; - } - -} - -/* sadly this is not stateless, but was the only way to serialize chunks one at a time */ -static uint8_t GetNextMatrixCallback(uint8_t isFirst,const_MatDesc_t * pdesc,void * data) { - - - Encoder_t * encodedata = (Encoder_t *)data; - - const AudioFeatureChunk_t * pchunk; - int16_t * bufptr16 = (int16_t *) &encodedata->unpackedbuffer[0][0]; - const int16_t * beginning16 = (int16_t *) &encodedata->unpackedbuffer[0][0]; - - uint32_t i; - const uint32_t chunk_buf_size = encodedata->buf->chunk_buf_size; - const uint32_t numchunkbuf = encodedata->buf->numchunkbuf; - //assert(encodedata->buf == &_buffer); - - memset(pdesc,0,sizeof(const_MatDesc_t)); - - if (encodedata->buf->numchunkbuf == 0 || encodedata->buf->pchunkbuf == NULL) { - return MAT_MESSAGE_FAIL; //stop - } - - if (isFirst) { - encodedata->currentidx = 0; - encodedata->endidx = encodedata->buf->chunkbufidx; - - if (chunk_buf_size == numchunkbuf) { - encodedata->currentidx = encodedata->buf->chunkbufidx + 1; //oldest untouched - - if (encodedata->currentidx >= chunk_buf_size) { - encodedata->currentidx -= chunk_buf_size; - } - } - - encodedata->state = 1; - } - - pchunk = &encodedata->buf->pchunkbuf[encodedata->currentidx]; - - pdesc->t1 = pchunk->samplecount; - pdesc->t2 = pdesc->t1 + BUF_SIZE_IN_CHUNK*2; //*2 because we are decimating audio samples by 2 - - - if (encodedata->state == 1) { - pdesc->id = k_id_feature_chunk; - - for (i = 0; i < BUF_SIZE_IN_CHUNK; i++) { - UnpackFeats8(encodedata->unpackedbuffer[i], pchunk->packedbuf[i]); - } - -/* - for (int j = 0; j < BUF_SIZE_IN_CHUNK; j++) { - printf("up="); - for (i = 0; i < NUM_AUDIO_FEATURES; i++) { - printf("%d,",encodedata->unpackedbuffer[j][i]); - } - printf("\n"); - - } -*/ - - - pdesc->data.len = BUF_SIZE_IN_CHUNK * NUM_AUDIO_FEATURES; - pdesc->data.type = esint8; - pdesc->data.data.sint8 = &encodedata->unpackedbuffer[0][0]; - pdesc->rows = BUF_SIZE_IN_CHUNK; - pdesc->cols = NUM_AUDIO_FEATURES; - - encodedata->state = 2; - - } - else if (encodedata->state == 2) { - pdesc->id = k_id_energy_chunk; - - //re-use the unpacked buffer, but let's pretend it's 16 bit... - for (i = 0; i < BUF_SIZE_IN_CHUNK; i++) { - *bufptr16 = pchunk->energy[i]; - bufptr16++; - } - - /* - for (i = 0; i < BUF_SIZE_IN_CHUNK + 1; i++) { - printf("%d,",beginning16[i]); - } - printf("\n"); - */ - - - pdesc->data.len = BUF_SIZE_IN_CHUNK; - pdesc->data.type = esint16; - pdesc->data.data.sint16 = beginning16; - pdesc->rows = 1; - pdesc->cols = BUF_SIZE_IN_CHUNK; - - encodedata->state = 1; - encodedata->currentidx++; - - //wrap - if (encodedata->currentidx >= chunk_buf_size) { - encodedata->currentidx -= chunk_buf_size; - } - - //have we reached the end? - if (encodedata->currentidx == encodedata->endidx) { - encodedata->state = 0; - return MAT_MESSAGE_DONE; - } - - } - - return MAT_MESSAGE_CONTINUE; -} - -void AudioClassifier_ResetStorageBuffer(void) { - /* Buffer read out? Great, let's reset it */ - - _buffer.chunkbufidx = 0; - _buffer.numchunkbuf = 0; -} - -#include "proto_utils.h" -#include "proto_utils.h" -#include "sys_time.h" -#include "matrix.pb.h" -#include "debugutils/matmessageutils.h" - -#ifdef USED_ON_DESKTOP -uint32_t get_time(void) { - return 0; -} - -bool encode_device_id_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) { - const char * k_device_id = "DESKTOP"; - return pb_encode_tag_for_field(stream, field) && pb_encode_string(stream, (uint8_t*)k_device_id, strlen(k_device_id)); -} - -#endif - -void * getMatrixClientMessage() { - //this code leaks references to these, can't have them on the stack - //also makes this function non reentrant - static Encoder_t encoderstruct; - static MatrixClientMessage mess; - static MatrixListEncodeContext_t matrix_list_context; - - memset(&mess, 0, sizeof(mess)); - mess.unix_time = get_time(); - mess.has_unix_time = 1; - mess.has_matrix_payload = 0; - - memset(&matrix_list_context, 0, sizeof(matrix_list_context)); - memset(&encoderstruct, 0, sizeof(encoderstruct)); - encoderstruct.buf = &_buffer; - - matrix_list_context.data = &encoderstruct; - matrix_list_context.func = GetNextMatrixCallback; - - mess.matrix_list.funcs.encode = write_mat_array; - mess.matrix_list.arg = (void *) &matrix_list_context; - mess.device_id.funcs.encode = encode_device_id_string; - - return &mess; -} diff --git a/kitsune/audioclassifier.h b/kitsune/audioclassifier.h deleted file mode 100644 index 1aff3f90..00000000 --- a/kitsune/audioclassifier.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _AUDIOCLASSIFIER_H_ -#define _AUDIOCLASSIFIER_H_ - -#include -#include "audio_types.h" -#include "machinelearning/machine_learning_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void AudioClassifier_Init(RecordAudioCallback_t recordfunc); - -void AudioClassifier_SetStorageBuffers(void * buffer, uint32_t buf_size_in_bytes); - -void AudioClassifier_DataCallback(AudioFeatures_t * pfeats); - -uint32_t AudioClassifier_EncodeAudioFeatures(pb_ostream_t * stream, void * encode_data); - -void AudioClassifier_ResetStorageBuffer(void); - -void * getMatrixClientMessage(); - -#ifdef __cplusplus -} -#endif - - - -#endif //#ifndef _AUDIOCLASSIFIER_H_ - diff --git a/kitsune/audiofeatures.c b/kitsune/audiofeatures.c index 5f7e3099..f0384758 100644 --- a/kitsune/audiofeatures.c +++ b/kitsune/audiofeatures.c @@ -1,40 +1,23 @@ #include "audiofeatures.h" #include "fft.h" +#include #include #include /* abs */ #include "debugutils/debuglog.h" #include #include "hellomath.h" - +#include "tensor/features_types.h" #ifdef USED_ON_DESKTOP #define LOGA(...) +#include #else #include "uart_logger.h" +#include "kit_assert.h" #endif #define TOFIX(x,q)\ ((int32_t) ((x) * (float)(1 << (q)))) -/* - How is this all going to work? - -Extract features, one of which is total energy - -If average energy over some period is stable, then - - 1) See if this frame of features is similar to others. - 2) If not similar, store feature vector in memory - 3) Report this frame as being - a. interesting, - b. interesting but already observed (i.e. similar) - c. totally fucking uninteresting (ah, blissful silence) - 4) Some other piece of code will later - - - -Potential pitfalls as is: - - impulse noises may not register at all, but will certainly be noticed by a human - well we'll deal with that later, I can already think of a processing scheme to incorporate this. - */ - /*-------------------------------- * Memory sizes, constants, macros, and related items @@ -45,8 +28,9 @@ #define PSD_SIZE_2N (5) #define PSD_SIZE (1 << PSD_SIZE_2N) -#define SAMPLE_RATE_IN_HZ (EXPECTED_AUDIO_SAMPLE_RATE_HZ / AUDIO_FFT_SIZE) -#define SAMPLE_PERIOD_IN_MILLISECONDS (1000 / SAMPLE_RATE_IN_HZ) +#define FRAME_AVG_BUF_SIZE_2N (2) +#define FRAME_AVG_BUF_SIZE (1 << FRAME_AVG_BUF_SIZE_2N) +#define FRAME_AVG_BUF_MASK (FRAME_AVG_BUF_SIZE - 1) #define ENERGY_BUF_SIZE_2N (4) #define ENERGY_BUF_SIZE (1 << ENERGY_BUF_SIZE_2N) @@ -56,30 +40,14 @@ #define CHANGE_SIGNAL_BUF_SIZE (1 << CHANGE_SIGNAL_BUF_SIZE_2N) #define CHANGE_SIGNAL_BUF_MASK (CHANGE_SIGNAL_BUF_SIZE - 1) -#define STEADY_STATE_AVERAGING_PERIOD_2N (6) -#define STEADY_STATE_AVERAGING_PERIOD (1 << STEADY_STATE_AVERAGING_PERIOD_2N) - -#ifdef NO_EQUALIZATION - #define STARTUP_PERIOD_IN_MS (0) -#else - //default - #define STARTUP_PERIOD_IN_MS (10000) -#endif - -#define STARTUP_EQUALIZATION_COUNTS (STARTUP_PERIOD_IN_MS / SAMPLE_PERIOD_IN_MILLISECONDS) - #define QFIXEDPOINT (12) #define TRUE (1) #define FALSE (0) -#define MICROPHONE_NOISE_FLOOR_DB (0.0f) +#define MICROPHONE_CALIBRATION_OFFSET (56.0f) -/* Have fun tuning these magic numbers! - Perhaps eventually we will have some pre-canned - data to show you how? */ - //the higher this gets, the less likely you are to be stable static const int16_t k_stable_likelihood_coefficient = TOFIX(1.0,QFIXEDPOINT); @@ -95,11 +63,6 @@ static const int32_t k_min_log_prob = TOFIX(-0.25f,QFIXEDPOINT); static const uint32_t k_stable_counts_to_be_considered_stable = STABLE_TIME_TO_BE_CONSIDERED_STABLE_IN_MILLISECONDS / SAMPLE_PERIOD_IN_MILLISECONDS; -/*-------------------------------- - * forward declarations - *--------------------------------*/ -void fix_window(int16_t fr[], int32_t n); - /*-------------------------------- * Types @@ -111,13 +74,10 @@ typedef enum { numChangeModes } EChangeModes_t; -typedef enum { - incoherent, - coherent, - numCoherencyModes -} ECoherencyModes_t; - typedef struct { + int16_t framebuf[FRAME_AVG_BUF_SIZE]; + int32_t frameaccumulator; + int16_t energybuf[ENERGY_BUF_SIZE];//32 bytes int32_t energyaccumulator; @@ -128,34 +88,23 @@ typedef struct { int16_t changebuf[CHANGE_SIGNAL_BUF_SIZE]; int32_t logProbOfModes[numChangeModes]; - int32_t logProbOfCoherencyModes[numCoherencyModes]; uint8_t isStable; int16_t energyStable; uint32_t stableCount; uint32_t stablePeriodCounter; - EChangeModes_t lastModes[3]; - int64_t modechangeTimes[3]; - uint8_t isValidSteadyStateSegment; - uint16_t psd_min_energy; + uint16_t min_energy; uint8_t statsLastIsStable; int16_t maxenergy; - AudioFeatureCallback_t fpCallback; - AudioOncePerMinuteDataCallback_t fpOncePerMinuteDataCallback; + AudioEnergyStatsCallback_t fpEnergyStatsResultsCallback; -} MelFeatures_t; - +} SimpleAudioFeatures_t; -typedef enum { - eAudioSignalIsNotInteresting, - eAudioSignalIsDiverse, - eAudioSignalIsSimilar -} EAudioSignalSimilarity_t; /*-------------------------------- * Static Memory Declarations *--------------------------------*/ -static MelFeatures_t _data; +static SimpleAudioFeatures_t _data; @@ -163,13 +112,13 @@ static MelFeatures_t _data; /*-------------------------------- * Functions *--------------------------------*/ -void init_background_energy(AudioOncePerMinuteDataCallback_t fpOncePerMinuteCallback) { +void init_background_energy(AudioEnergyStatsCallback_t fpOncePerMinuteCallback) { memset(&_data,0,sizeof(_data)); - _data.fpOncePerMinuteDataCallback = fpOncePerMinuteCallback; + _data.fpEnergyStatsResultsCallback = fpOncePerMinuteCallback; - _data.psd_min_energy = MIN_ENERGY; + _data.min_energy = MIN_ENERGY; } @@ -186,7 +135,7 @@ static int32_t GetAudioEnergyAsDBA(int16_t logenergy) { dba *= 3; //add microphone noise floor (measured) - dba += TOFIX(MICROPHONE_NOISE_FLOOR_DB,10); + dba += TOFIX(MICROPHONE_CALIBRATION_OFFSET,10); return dba; } @@ -211,14 +160,13 @@ static int16_t MovingAverage16(uint32_t counter, const int16_t x,int16_t * buf, } //finds stats of a disturbance, and performs callback when distubance is over -static void UpdateEnergyStats(uint8_t isStable,int16_t logTotalEnergyAvg,int16_t logTotalEnergy) { - AudioOncePerMinuteData_t data; - - data.num_disturbances = 0; +static void UpdateEnergyStats(EChangeModes_t changeMode, uint8_t isStable,int16_t logTotalEnergyAvg,int16_t logTotalEnergy) { + AudioEnergyStats_t data; + memset(&data,0,sizeof(data)); //leaving stable mode -- therefore starting a disturbance if (!isStable && _data.statsLastIsStable) { - //LOGI("S->US\r\n"); + //DISP("S->US\r\n"); _data.maxenergy = logTotalEnergy; } @@ -230,15 +178,15 @@ static void UpdateEnergyStats(uint8_t isStable,int16_t logTotalEnergyAvg,int16_t //entering stable mode --ending a disturbance if (isStable && !_data.statsLastIsStable ) { - //LOGI("US->S\r\n"); + //DISP("US->S\r\n"); data.num_disturbances = 1; } - if (_data.fpOncePerMinuteDataCallback) { + if (_data.fpEnergyStatsResultsCallback) { + data.disturbance_time_count = changeMode == stable ? 0 : SAMPLE_PERIOD_IN_MILLISECONDS; data.peak_background_energy = GetAudioEnergyAsDBA(logTotalEnergyAvg); data.peak_energy = GetAudioEnergyAsDBA(logTotalEnergy); - - _data.fpOncePerMinuteDataCallback(&data); + _data.fpEnergyStatsResultsCallback(&data); } @@ -250,7 +198,6 @@ static uint8_t IsStable(EChangeModes_t currentMode,const int16_t energySignal) { uint8_t isStable = FALSE; - if (currentMode != stable) { _data.stableCount = 0; } @@ -440,24 +387,69 @@ static void UpdateChangeSignals(EChangeModes_t * pCurrentMode, const int16_t new } -void set_background_energy(const int16_t fr[], const int16_t fi[]) { - //enjoy this nice large stack. - //this can all go away if we get fftr to work, and do the - int16_t psd[PSD_SIZE]; - uint8_t log2scaleOfRawSignal; - int16_t logTotalEnergy; - int16_t logTotalEnergyAvg; +__attribute__((section(".ramcode"))) +static void getvolume(int16_t * logTotalEnergy, const int16_t * fr,const int16_t * fi,uint16_t min_energy, const int16_t log2scale) { + uint64_t utemp64; + uint64_t non_weighted_energy = 0; + uint64_t a_weighted_energy = 0; + int32_t temp32; + + //from 0 - 8Khz + const static uint16_t a_weight_q10[128] = { 0, 0, 100, 150, 263, 379, 489, + 510, 725, 763, 823, 859, 896, 934, 963, 994, 1024, 1054, 1085, 1093, + 1101, 1110, 1123, 1136, 1149, 1152, 1156, 1159, 1162, 1166, 1169, + 1172, 1176, 1166, 1170, 1174, 1178, 1182, 1184, 1185, 1187, 1188, + 1189, 1185, 1180, 1176, 1171, 1167, 1162, 1162, 1162, 1162, 1162, + 1162, 1162, 1162, 1161, 1159, 1157, 1156, 1154, 1152, 1151, 1149, + 1146, 1142, 1139, 1136, 1133, 1129, 1126, 1123, 1120, 1116, 1112, + 1107, 1103, 1098, 1094, 1089, 1085, 1081, 1076, 1072, 1067, 1063, + 1059, 1054, 1050, 1046, 1042, 1037, 1033, 1029, 1025, 1021, 1016, + 1012, 1012, 1009, 1005, 1002, 998, 995, 991, 987, 984, 981, 977, + 974, 970, 967, 963, 959, 956, 952, 948, 945, 941, 937, 934, 930, + 927, 923, 920, 916, 913, 913 }; + + uint16_t idx, ifft; + + const int16_t idx_shift = FEATURES_FFT_SIZE_2N - 8; + + for (ifft = 1; ifft < FEATURES_FFT_SIZE/2; ifft++) { + utemp64 = 0; + utemp64 += (int32_t)fr[ifft]*(int32_t)fr[ifft]; + utemp64 += (int32_t)fi[ifft]*(int32_t)fi[ifft]; + + idx = ifft >> idx_shift; + assert(idx < 128); + + a_weighted_energy += (utemp64 * a_weight_q10[idx]) >> 10; + non_weighted_energy += utemp64; + } + + + temp32 = FixedPointLog2Q10(a_weighted_energy + min_energy) - 2 * log2scale*1024; + + if (temp32 > INT16_MAX) { + temp32 = INT16_MAX; + } + + if (temp32 < INT16_MIN) { + temp32 = INT16_MIN; + } + + *logTotalEnergy = (int16_t)temp32; + +} + + +void set_background_energy(const int16_t fr[], const int16_t fi[], int16_t log2scale) { + int16_t logTotalEnergy = 0; + int16_t logTotalEnergyAvg = 0; EChangeModes_t currentMode; uint8_t isStable; - /* Normalize time series signal */ - //ScaleInt16Vector(fr,&log2scaleOfRawSignal,AUDIO_FFT_SIZE,RAW_SAMPLES_SCALE); - log2scaleOfRawSignal = 0; - - /* Get PSD of variously spaced non-overlapping frequency windows*/ - logpsdmel(&logTotalEnergy,psd,fr,fi,log2scaleOfRawSignal,_data.psd_min_energy); //psd is now 64, and on a logarithmic scale after 1khz + /* compute volume */ + getvolume(&logTotalEnergy,fr,fi,_data.min_energy,log2scale); /* Determine stability of signal energy order to figure out when to estimate background spectrum */ logTotalEnergyAvg = MovingAverage16(_data.callcounter, logTotalEnergy, _data.energybuf, &_data.energyaccumulator,ENERGY_BUF_MASK,ENERGY_BUF_SIZE_2N); @@ -467,20 +459,22 @@ void set_background_energy(const int16_t fr[], const int16_t fi[]) { * that all the audio we are hearing is just background noise */ UpdateChangeSignals(¤tMode, logTotalEnergyAvg, _data.callcounter); - isStable = IsStable(currentMode,logTotalEnergyAvg); - //if (c++ == 255) { - LOGA("%d\n",GetAudioEnergyAsDBA(logTotalEnergyAvg)); - //} + /* human pereption is ~50 ms, so we average volume over 4 frames (60 ms) */ + logTotalEnergy = MovingAverage16(_data.callcounter, logTotalEnergy, _data.framebuf, &_data.frameaccumulator,FRAME_AVG_BUF_MASK,FRAME_AVG_BUF_SIZE_2N); - UpdateEnergyStats(isStable,logTotalEnergyAvg,logTotalEnergy); + UpdateEnergyStats(currentMode,isStable,logTotalEnergyAvg,logTotalEnergy); _data.lastEnergy = logTotalEnergy; - /* Update counter. It's okay if this one rolls over*/ _data.callcounter++; + /* + if (_data.callcounter % 66 == 0) { + DISP("vol_energy=%d\r\n",GetAudioEnergyAsDBA(logTotalEnergyAvg)); + } +*/ } diff --git a/kitsune/audiofeatures.h b/kitsune/audiofeatures.h index 3e9d0952..ed6bbc53 100644 --- a/kitsune/audiofeatures.h +++ b/kitsune/audiofeatures.h @@ -11,14 +11,12 @@ extern "C" { #endif - - /* exported for your enjoyment -- use these! */ -void init_background_energy(AudioOncePerMinuteDataCallback_t fpOncePerMinuteCallback); +void init_background_energy(AudioEnergyStatsCallback_t fpOncePerMinuteCallback); -/* Expects AUDIO_FFT_SIZE samples in samplebuf */ -void set_background_energy(const int16_t fr[], const int16_t fi[]); +/* Expects FEATURES_FFT_SIZE samples in samplebuf */ +void set_background_energy(const int16_t fr[], const int16_t fi[], int16_t log2scale); #ifdef __cplusplus } diff --git a/kitsune/audiosimilarity.c b/kitsune/audiosimilarity.c deleted file mode 100644 index 6a980667..00000000 --- a/kitsune/audiosimilarity.c +++ /dev/null @@ -1,431 +0,0 @@ -#include "audioclassifier.h" -#include -#include -#include /* abs */ -#include -#include "fft.h" -#include "debugutils/debuglog.h" -#include "debugutils/matmessageutils.h" - - - -#define ITEMS_SIZE_2N (8) -#define ITEMS_SIZE (1 << ITEMS_SIZE_2N) -#define ITEMS_SIZE_MASK (ITEMS_SIZE - 1) - -#define NUM_LIST_ITEMS (32) - -#define SIMILARITY_THRESHOLD (0.707f) - -/****************** - typedefs - *****************/ - - -typedef struct ListItem { - uint8_t listidx; - uint8_t updatecount; - struct ListItem * next; - struct ListItem * prev; -} ListItem_t; //~12 bytes - - -typedef struct { - /* For similarity */ - int8_t feats[NUM_LIST_ITEMS][NUM_AUDIO_FEATURES]; //32 * 16 = 512 bytes - uint8_t featsidx[NUM_LIST_ITEMS]; //32 bytes - ListItem_t listdata[NUM_LIST_ITEMS];//32 * 12 = 384 bytes - uint16_t featModeIndex; - - /* For storage */ - uint8_t occurencesindices[ITEMS_SIZE]; //256 bytes - uint8_t occurenceDurations[ITEMS_SIZE]; //256 bytes - uint16_t occurenceDeltaTimeSinceLastSegment[ITEMS_SIZE]; //512 bytes - //int8_t occurencesfeats[ITEMS_SIZE][NUM_AUDIO_FEATURES]; //32 * 16 = 512 bytes - - - uint16_t occurenceidx; - - uint16_t numItemsInOccurenceBuffer; - NotificationCallback_t fpNovelDataCallback; - int64_t lastUpdateTime; - int64_t firstUpdateTime; - uint8_t updateCountNoveltyThreshold; - - -} AudioClassifier_t; - - - -/****************** - static memory - *****************/ -static const int16_t k_similarity_threshold = TOFIX(SIMILARITY_THRESHOLD,10); -static const char * k_occurence_indices_buf_id = "occurenceIndices"; -static const char * k_occurence_durations_buf_id = "occurenceDurations"; -static const char * k_occurence_deltatimes_buf_id = "occurenceDeltaTimes"; -static const char * k_feat_vec_buf_id = "featVecs"; -static const char * k_feat_index_buf_id = "featIndices"; -static const char * k_occurence_info_buf_id = "occurenceInfo"; - -static ListItem_t * _pHead; -static ListItem_t * _pFree; -static ListItem_t * _pTail; - -static AudioClassifier_t _data; - - -/****************** - static functions - *****************/ -static ListItem_t * FindSimilarItem(const int8_t * featvec8) { - - int16_t cosvec; - ListItem_t * p; - int8_t * feat; - - //go through list to all stored feature vectors - //take dot product, normalized, of featvec8 with stored feat vecs - //if cosine of angle is greater than some threshold, we consider - //these vectors similar - p = _pHead; - while(p) { - feat = _data.feats[p->listidx]; - - //take dot product of each feature vector - cosvec = cosvec8(feat, featvec8, NUM_AUDIO_FEATURES); - - //if similar enough - if (cosvec > k_similarity_threshold) { - break; - } - - p = p->next; - } - - return p; -} - - -/* - List is arranged in descending order in time - - If the list fills up (i.e. no more free elements) we pop off the last - element in the list. - - Otherwise, we insert an element in the list - */ -static ListItem_t * AddItemToHeadOfList(const int8_t * featvec8,const Segment_t * pSeg) { - ListItem_t * p; - int8_t * featdata; - - //kill oldest item if we have no free space - if (_pFree == NULL) { - - if (!_pTail) { - //! \todo LOG ERROR! - return NULL; - } - - //pop - _pFree = _pTail; - _pTail = _pTail->prev; - - //terminate end - _pTail->next = NULL; - - _pFree->prev = NULL; - } - - //we will always have a free item here - if (!_pHead) { - //first add - _pHead = _pFree; - _pFree = _pFree->next; - _pHead->next = NULL; - _pFree->prev = NULL; - _pTail = _pHead; - } - else { - //insert new item at top - p = _pHead; //old head is p - - //new head is free - _pHead = _pFree; - - //pop head of free list - _pFree = _pFree->next; - if (_pFree) { - _pFree->prev = NULL; - } - - //new head next is old head - _pHead->next = p; - - //old head prev is new head - p->prev = _pHead; - } - - featdata = _data.feats[_pHead->listidx]; - - memcpy(featdata,featvec8,sizeof(int8_t)*NUM_AUDIO_FEATURES); - _data.featsidx[_pHead->listidx] = _data.featModeIndex; - _pHead->updatecount = 0; - return _pHead; -} - -static void MoveItemToHeadOfList(ListItem_t * p) { - - //I'm the head? - if (!p->prev) { - //yes so do nothing - return; - } - - //am I the tail? - if (!p->next) { - //yes, so pop from tail - _pTail = p->prev; - _pTail->next = NULL; - } - else { - //pop from the middle of the list - p->prev->next = p->next; - p->next->prev = p->prev; - } - - p->next = _pHead; - - _pHead = p; - _pHead->next->prev = _pHead; - _pHead->prev = NULL; - - -} - - - - - - -/****************** - exported functions - *****************/ - -void AudioClassifier_Init(uint8_t updateCountNoveltyThreshold,NotificationCallback_t novelDataCallback,MutexCallback_t fpLock, MutexCallback_t fpUnlock) { - uint16_t i; - - _data.fpNovelDataCallback = novelDataCallback; - - //set up the link list - memset(&_data,0,sizeof(AudioClassifier_t)); - - _pFree = &_data.listdata[0]; - _pHead = NULL; - _pTail = NULL; - for (i = 0; i < NUM_LIST_ITEMS - 1; i++) { - _data.listdata[i].next = &_data.listdata[i+1]; - _data.listdata[i+1].prev = &_data.listdata[i]; - } - - for (i = 0; i < NUM_LIST_ITEMS; i++) { - _data.listdata[i].listidx = i; - } - - _data.updateCountNoveltyThreshold = updateCountNoveltyThreshold; - _data.fpUnlock = fpUnlock; - _data.fpLock = fpLock; -} - -/* Call this after you pull the buffer */ -void AudioClassifier_ResetUpdateTime(void) { - - if (_data.fpLock) { - _data.fpLock(); - } - - _data.firstUpdateTime = 0; - _data.numItemsInOccurenceBuffer = 0; - - if (_data.fpUnlock) { - _data.fpUnlock(); - } -} - -/* - - - Set stream to NULL to get size of written buffer - - Set source and tags to NULL if you want. - - */ -uint32_t AudioClassifier_GetSerializedBuffer(pb_ostream_t * stream,const char * macbytes, uint32_t unix_time,const char * tags, const char * source) { - - uint32_t size = 0; - - - if (_data.fpLock) { - _data.fpLock(); - } - - { - const uint16_t info[2] = {_data.occurenceidx,_data.numItemsInOccurenceBuffer}; - - MatDesc_t descs[6] = { - {k_occurence_info_buf_id,tags,source,{},1,2,_data.firstUpdateTime,_data.lastUpdateTime}, - {k_occurence_indices_buf_id,tags,source,{},1,_data.numItemsInOccurenceBuffer,_data.firstUpdateTime,_data.lastUpdateTime}, - {k_occurence_durations_buf_id,tags,source,{},1,_data.numItemsInOccurenceBuffer,_data.firstUpdateTime,_data.lastUpdateTime}, - {k_occurence_deltatimes_buf_id,tags,source,{},1,_data.numItemsInOccurenceBuffer,_data.firstUpdateTime,_data.lastUpdateTime}, - {k_feat_index_buf_id,tags,source,{},1,NUM_LIST_ITEMS,_data.firstUpdateTime,_data.lastUpdateTime}, - {k_feat_vec_buf_id,tags,source,{},NUM_LIST_ITEMS,NUM_AUDIO_FEATURES,_data.firstUpdateTime,_data.lastUpdateTime}, - }; - - /*****************/ - descs[0].data.len = 2; - descs[0].data.type = euint16; - descs[0].data.data.uint16 = info; - - /*****************/ - descs[1].data.len = _data.numItemsInOccurenceBuffer; - descs[1].data.type = euint8; - descs[1].data.data.uint8 = _data.occurencesindices; - - /*****************/ - descs[2].data.len = _data.numItemsInOccurenceBuffer; - descs[2].data.type = euint8; - descs[2].data.data.uint8 = _data.occurenceDurations; - - /*****************/ - descs[3].data.len = _data.numItemsInOccurenceBuffer; - descs[3].data.type = euint16; - descs[3].data.data.uint16 = _data.occurenceDeltaTimeSinceLastSegment; - - /*****************/ - descs[4].data.len = NUM_LIST_ITEMS; - descs[4].data.type = euint8; - descs[4].data.data.uint8 = _data.featsidx; - - /*****************/ - descs[5].data.len = NUM_LIST_ITEMS*NUM_AUDIO_FEATURES; - descs[5].data.type = esint8; - descs[5].data.data.sint8 = &_data.feats[0][0]; - - - size = SetMatrixMessage(stream, macbytes, unix_time, descs, sizeof(descs) / sizeof(MatDesc_t)); - } - - - if (_data.fpUnlock) { - _data.fpUnlock(); - } - - return size; -} - - - -void AudioClassifier_DataCallback(int64_t samplecount, const AudioFeatures_t * feats) { - - uint8_t isNovel = FALSE; - - if (_data.fpLock) { - _data.fpLock(); - } - - { - int8_t featvec8[NUM_AUDIO_FEATURES]; - ListItem_t * pitem; - uint8_t duration; - int64_t deltaTimeSinceLastUpdate; - - //scale to int8 - Scale16VecTo8(featvec8,feats,NUM_AUDIO_FEATURES); - - //go through list and find a similar item (potentially NUM_LIST_ITEMS dot products) - pitem = FindSimilarItem(featvec8); - - if (pitem) { - //we found a similar item! - MoveItemToHeadOfList(pitem); - } - else { - //add similarity vector, because this is phresh - pitem = AddItemToHeadOfList(featvec8,pSegment); - - //increment (and possibly even rollover) our index number for the features - _data.featModeIndex++; - } - - //safety first - if (pitem) { - - //for the first N new feature vectors, let someone know that this is a new sound - if (pitem->updatecount++ < _data.updateCountNoveltyThreshold) { - isNovel = TRUE; - } - - - //compute how long it's been since the last segment came in - deltaTimeSinceLastUpdate = pSegment->t1 - _data.lastUpdateTime; - _data.lastUpdateTime = pSegment->t1; - - if (deltaTimeSinceLastUpdate > UINT16_MAX) { - deltaTimeSinceLastUpdate = UINT16_MAX; - } - - _data.occurenceDeltaTimeSinceLastSegment[_data.occurenceidx] = (uint16_t)deltaTimeSinceLastUpdate; - - if (!_data.firstUpdateTime) { - _data.firstUpdateTime = pSegment->t1; - } - - //add occurence to circular buffer, give it index of the feature vector to which is associated - _data.occurencesindices[_data.occurenceidx] = _data.featsidx[pitem->listidx]; - - //compute duration - if (pSegment->duration > UINT8_MAX) { - duration = UINT8_MAX; - } - else { - duration = pSegment->duration; - } - - _data.occurenceDurations[_data.occurenceidx] = duration; - - - //update occurence index, wrapping as necessary - _data.occurenceidx++; - _data.occurenceidx &= ITEMS_SIZE_MASK; - - //update number of items in occurence buffer - if (++_data.numItemsInOccurenceBuffer > ITEMS_SIZE ) { - _data.numItemsInOccurenceBuffer = ITEMS_SIZE; - } - - } - } - - if (_data.fpUnlock) { - _data.fpUnlock(); - } - - if (isNovel && _data.fpNovelDataCallback) { - _data.fpNovelDataCallback(); - } - -} - - - - - - - - - - - - - - - - diff --git a/kitsune/audiosimilarity.h b/kitsune/audiosimilarity.h deleted file mode 100644 index e7c8cf77..00000000 --- a/kitsune/audiosimilarity.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _AUDIOSIMILARITY_H_ -#define _AUDIOSIMILARITY_H_ - -#include "audio_types.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void AudioClassifier_Init(uint8_t updateCountNoveltyThreshold,NotificationCallback_t novelDataCallback,MutexCallback_t fpLock, MutexCallback_t fpUnlock); - -void AudioClassifier_ResetUpdateTime(void); - -uint32_t AudioClassifier_GetSerializedBuffer(pb_ostream_t * stream,const char * macbytes, uint32_t unix_time,const char * tags, const char * source); - -void AudioClassifier_DataCallback(AudioFeatures_t * feats); - -#ifdef __cplusplus -} -#endif - - -#endif - diff --git a/kitsune/audiotask.c b/kitsune/audiotask.c index 9991d593..ed43a6eb 100644 --- a/kitsune/audiotask.c +++ b/kitsune/audiotask.c @@ -225,9 +225,15 @@ static void _playback_loop(AudioPlaybackDesc_t * desc, hlo_stream_signal sig_sto hlo_stream_t * fs = desc->stream; if(vol_ramp) { + int ramp_target = desc->volume; + if(ramp_target > 64){ + ramp_target = 64; + }else if(ramp_target < 0){ + ramp_target = 0; + } vol = (ramp_ctx_t){ .current = 0, - .target = desc->volume, + .target = ramp_target, .ramp_up_ms = desc->fade_in_ms / (desc->volume + 1), .ramp_down_ms = desc->fade_out_ms / (desc->volume + 1), .duration = desc->durationInSeconds * 1000, diff --git a/kitsune/audiotask.h b/kitsune/audiotask.h index 47d4cda4..81c89b4c 100644 --- a/kitsune/audiotask.h +++ b/kitsune/audiotask.h @@ -46,7 +46,7 @@ void AudioPlaybackTask(void * data); void AudioTask_StartPlayback(const AudioPlaybackDesc_t * desc); void AudioTask_StopPlayback(void); -void AudioTask_DumpOncePerMinuteStats(AudioOncePerMinuteData_t * pdata); +void AudioTask_DumpOncePerMinuteStats(AudioEnergyStats_t * pdata); /** * testing commands */ diff --git a/kitsune/ble_proto.c b/kitsune/ble_proto.c index aa2d1e6d..5c35547a 100644 --- a/kitsune/ble_proto.c +++ b/kitsune/ble_proto.c @@ -670,7 +670,7 @@ void play_startup_sound() { memset(&desc, 0, sizeof(desc)); desc.stream = fs_stream_open(STARTUP_SOUND_NAME, HLO_STREAM_READ); ustrncpy(desc.source_name, STARTUP_SOUND_NAME, sizeof(desc.source_name)); - desc.volume = 64; + desc.volume = 48; desc.durationInSeconds = -1; desc.rate = AUDIO_SAMPLE_RATE; desc.fade_in_ms = 0; diff --git a/kitsune/codec/hlo_lossless.c b/kitsune/codec/hlo_lossless.c index 447b7009..9dcfbf61 100644 --- a/kitsune/codec/hlo_lossless.c +++ b/kitsune/codec/hlo_lossless.c @@ -1,6 +1,5 @@ #include "codec/hlo_lossless.h" -#include "codec/lpc.h" #include "codec/rice.h" //Block size is in samples ! @@ -9,13 +8,12 @@ static const int32_t sample_rate = 16000; static const int16_t bps = 16; static const int8_t channels = 1; static const int32_t estimated_frames = 800; //6 seconds -static const int16_t Q = 35; -static const int64_t corr = ((int64_t)1) << Q; static const char magic_number[5] = "hello"; static const uint32_t frame_sync = 0xAA55FF00; static const int samples_per_channel = BLOCK_SIZE; +#include "uart_logger.h" hlo_stream_t * hlo_lossless_init_chunkbuf( int size ) { return circ_stream_open(size); } @@ -23,31 +21,38 @@ int hlo_lossless_write_chunkbuf( hlo_stream_t * s, int16_t short_samples[] ) { return hlo_lossless_write_frame(s, short_samples); } int hlo_lossless_dump_chunkbuf( hlo_stream_t * s, hlo_stream_t * output ) { - uint32_t word; + uint32_t word,w=0; int ret = 1; + int ret_out = 1; uint8_t buf[512]; //scan for frame sync - while( ret ) { + while( 1 ) { ret = hlo_stream_transfer_all(FROM_STREAM, s, (uint8_t*)&word,sizeof(int32_t), 4); if (ret < 0 ) break; + w++; //since we are guaranteed writes work on the circ stream there much be a whole number //of frames after the first sync. It's possible frames of different sizes come in, in which case //an incoming frame could eat the header off the eldest frame to make room if( word == frame_sync ) { + DISP("got sync at %d\n", 4*w); hlo_lossless_start_stream(output); - ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&frame_sync,sizeof(int32_t), 4); - if (ret < 0 ) break; - ret = hlo_stream_transfer_between(s,output,buf,sizeof(buf),4); - if (ret < 0 ) break; + ret_out = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&frame_sync,sizeof(int32_t), 4); + if (ret_out < 0 ) break; + while( ret >= 0 ) { + int ret = hlo_stream_transfer_all(FROM_STREAM, s, buf,sizeof(buf), 4 ); + if(ret < 0) break; + ret_out = hlo_stream_transfer_all(INTO_STREAM, output, buf,sizeof(buf), 4 ); + if (ret_out < 0 ) break; + } } } hlo_stream_close(s); - return ret; + return ret_out; } int hlo_lossless_start_stream( hlo_stream_t * output) { - int ret = 1; + int ret = 0; ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&magic_number,sizeof(magic_number), 4); if (ret < 0 ) return ret; ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&sample_rate,sizeof(int32_t), 4); @@ -63,25 +68,15 @@ int hlo_lossless_write_frame(hlo_stream_t * output, int16_t short_samples[] ) { //Define read size int32_t i,j = 0; int16_t * buffer = short_samples; - int ret = 1; + int ret = 0; - int32_t qtz_ref_coeffs[MAX_LPC_ORDER]; - int32_t int_samples[BLOCK_SIZE]; int32_t residues[BLOCK_SIZE]; - uint32_t unsigned_ref[MAX_LPC_ORDER]; - uint32_t encoded_ref[MAX_LPC_ORDER]; uint32_t u_residues[BLOCK_SIZE]; uint32_t encoded_residues[BLOCK_SIZE]; - int64_t lpc[MAX_LPC_ORDER + 1]; - int32_t qtz_samples[BLOCK_SIZE]; - int32_t autocorr[MAX_LPC_ORDER + 1]; - int32_t ref[MAX_LPC_ORDER]; - int32_t lpc_mat[MAX_LPC_ORDER][MAX_LPC_ORDER]; - uint8_t opt_lpc_order; - uint8_t rice_param_ref,rice_param_residue; - uint16_t req_int_ref,req_int_residues; - uint32_t req_bits_ref,req_bits_residues; + uint8_t rice_param_residue; + uint16_t req_int_residues; + uint32_t req_bits_residues; ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&frame_sync,sizeof(int32_t), 4); if (ret < 0 ) return ret; @@ -89,74 +84,20 @@ int hlo_lossless_write_frame(hlo_stream_t * output, int16_t short_samples[] ) { { //Separate channels for(j = 0; j < samples_per_channel; j++) - short_samples[j] = buffer[channels * j + i]; - //Quantize sample data - for(j = 0; j < samples_per_channel; j++) - qtz_samples[j] = (short_samples[j]<<15); - //Calculate autocorrelation data - auto_corr_fun(qtz_samples,samples_per_channel,MAX_LPC_ORDER,1, - autocorr); - //Calculate reflection coefficients - opt_lpc_order = compute_ref_coefs(autocorr,MAX_LPC_ORDER,ref); - //Quantize reflection coefficients - qtz_ref_cof(ref,opt_lpc_order,qtz_ref_coeffs); - //signed to unsigned - signed_to_unsigned(opt_lpc_order,qtz_ref_coeffs,unsigned_ref); - - //get optimum rice param and number of bits - rice_param_ref = get_opt_rice_param(unsigned_ref,opt_lpc_order, - &req_bits_ref); - //Encode ref coeffs - req_bits_ref = rice_encode_block(rice_param_ref,unsigned_ref, - opt_lpc_order,encoded_ref); - //Determine number of ints required for storage - req_int_ref = (req_bits_ref+31)/(32); - - //Dequantize reflection - dqtz_ref_cof(qtz_ref_coeffs,opt_lpc_order,ref); - - //Reflection to lpc - levinson(NULL,opt_lpc_order,ref,lpc_mat); - - lpc[0] = 0; - for(j = 0; j < opt_lpc_order; j++) - lpc[j + 1] = corr * lpc_mat[opt_lpc_order - 1][j]; - - for(j = opt_lpc_order; j < MAX_LPC_ORDER; j++) - lpc[j + 1] = 0; - - //Copy samples - for(j = 0; j < samples_per_channel; j++) - int_samples[j] = short_samples[j]; - - //Get residues - calc_residue(int_samples,samples_per_channel,opt_lpc_order,Q,lpc, - residues); + residues[j] = buffer[channels * j + i]; //signed to unsigned signed_to_unsigned(samples_per_channel,residues,u_residues); //get optimum rice param and number of bits - rice_param_residue = get_opt_rice_param(u_residues, - samples_per_channel,&req_bits_residues); + rice_param_residue = get_opt_rice_param(u_residues,samples_per_channel,&req_bits_residues); //Encode residues - req_bits_residues = rice_encode_block(rice_param_residue,u_residues, - samples_per_channel,encoded_residues); + req_bits_residues = rice_encode_block(rice_param_residue,u_residues, samples_per_channel,encoded_residues); //Determine nunber of ints required for storage req_int_residues = (req_bits_residues+31)/(32); - //Write rice_params,bytes,encoded lpc_coeffs to output - ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&rice_param_ref,sizeof(uint8_t), 4); - if (ret < 0 ) break; - ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&req_int_ref,sizeof(uint16_t), 4); - if (ret < 0 ) break; - ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&opt_lpc_order,sizeof(uint8_t), 4); - if (ret < 0 ) break; - ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)encoded_ref,req_int_ref*sizeof(uint32_t), 4); - if (ret < 0 ) break; - //Write rice_params,bytes,encoded residues to output ret = hlo_stream_transfer_all(INTO_STREAM, output, (uint8_t*)&rice_param_residue,sizeof(uint8_t), 4); if (ret < 0 ) break; @@ -168,19 +109,31 @@ int hlo_lossless_write_frame(hlo_stream_t * output, int16_t short_samples[] ) { } return ret; } - +extern volatile unsigned int idlecnt; +#include "FreeRTOS.h" +#include "task.h" int hlo_filter_lossless_encoder(hlo_stream_t * input, hlo_stream_t * output, void * ctx, hlo_stream_signal signal){ int16_t short_samples[BLOCK_SIZE]; int ret = hlo_lossless_start_stream(output); + //x $ftestt$b $i192.168.7.24 h + //x $a $i192.168.7.24 h + //x $a $i192.168.7.24 x + uint32_t got=0, sent=0; + idlecnt = 0; + TickType_t begin = xTaskGetTickCount(); while(1){ ret = hlo_stream_transfer_all(FROM_STREAM, input, (uint8_t*)short_samples, sizeof(short_samples) /*read_size*bps/8*/, 4); if (ret < 0 ) break; - + got += ret; ret = hlo_lossless_write_frame( output, short_samples /*, (ret/(bps/8))/channels*/ ); if (ret < 0 ) break; - + sent += ret; BREAK_ON_SIG(signal); } + DISP("%d idle\n", idlecnt); + DISP("%d kbps\n", (1000 * sent / (xTaskGetTickCount()-begin))/1024); + DISP("got %d, sent %d, ratio %d\n", got, sent, sent*100/got); + return ret; } diff --git a/kitsune/codec/lpc.c b/kitsune/codec/lpc.c deleted file mode 100644 index 9db40aa3..00000000 --- a/kitsune/codec/lpc.c +++ /dev/null @@ -1,248 +0,0 @@ -#include -#include -#include -#include - -#include "lpc.h" - -//Lookup Tables for 1st, 2nd and higher order quantized reflection coeffs -static const int32_t -lookup_1st_order_coeffs[128] = -{-2147483648,-2147221504,-2146435072,-2145124352,-2143289344,-2140930048,-2138046464,-2134638592,-2130706432,-2126249984,-2121269248,-2115764224,-2109734912,-2103181312,-2096103424,-2088501248,-2080374784,-2071724032,-2062548992,-2052849664,-2042626048,-2031878144,-2020605952,-2008809472,-1996488704,-1983643648,-1970274304,-1956380672,-1941962752,-1927020544,-1911554048,-1895563264,-1879048192,-1862008832,-1844445184,-1826357248,-1807745024,-1788608512,-1768947712,-1748762624,-1728053248,-1706819584,-1685061632,-1662779392,-1639972864,-1616642048,-1592786944,-1568407552,-1543503872,-1518075904,-1492123648,-1465647104,-1438646272,1411121152,-1383071744,-1354498048,-1325400064,-1295777792,-1265631232,-1234960384,-1203765248,-1172045824,-1139802112,-1107034112,-1073741824,-1039925248,-1005584384,-970719232,-935329792,-899416064,-862978048,-826015744,-788529152,-750518272,-711983104,-672923648,-633339904,-593231872,-552599552,-511442944,-469762048,-427556864,-384827392,-341573632,-297795584,-253493248,-208666624,-163315712,-117440512,-71041024,-24117248,23330816,71303168,119799808,168820736,218365952,268435456,319029248,370147328,421789696,473956352,526647296,579862528,633602048,687865856,742653952,797966336,853803008,910163968,967049216,1024458752,1082392576,1140850688,1199833088,1259339776,1319370752,1379926016,1441005568,1502609408,1564737536,1627389952,1690566656,1754267648,1818492928,1883242496,1948516352,2014314496,2080636928}; - -/*Checks if every sample of a block is equal or not*/ -int32_t check_if_constant(const int16_t *data,int32_t num_elements) -{ - int16_t temp = data[0]; - int i; - - for( i = 1; i < num_elements; i++) - { - if(temp != data[i]) - return -1; - } - - return 0; -} - -/*autocorrelation function*/ -void auto_corr_fun(int32_t *x,int32_t N,int64_t k,int16_t norm,int32_t *rxx) -{ - int64_t i, n; - int32_t sum = 0,mean = 0; - - for (i = 0; i < N; i++) - sum += x[i]; - mean = sum/N; - - for(i = 0; i <= k; i++) - { - rxx[i] = 0.0; - for (n = i; n < N; n++) - rxx[i] += ((int64_t)(x[n] - mean) * (x[n-i] - mean))>>15; - } - - if(norm) - { - for (i = 1; i <= k; i++) - rxx[i] /= rxx[0]; - rxx[0] = 1<<15; - } - - return; -} - -/*Levinson recursion algorithm*/ -void levinson(int32_t *autoc,uint8_t max_order,int32_t *ref,int32_t lpc[][MAX_LPC_ORDER]) -{ - int32_t i, j, i2; - int32_t r, err, tmp; - int32_t lpc_tmp[MAX_LPC_ORDER]; - - for(i = 0; i < max_order; i++) - lpc_tmp[i] = 0; - err = 1.0; - if(autoc) - err = autoc[0]; - - for(i = 0; i < max_order; i++) - { - if(ref) - r = ref[i]; - else - { - r = -autoc[i+1]; - for(j = 0; j < i; j++) - r -= lpc_tmp[j] * autoc[i-j]; - r /= err; - err *= 1.0 - (r * r); - } - - i2 = i >> 1; - lpc_tmp[i] = r; - for(j = 0; j < i2; j++) - { - tmp = lpc_tmp[j]; - lpc_tmp[j] += r * lpc_tmp[i-1-j]; - lpc_tmp[i-1-j] += r * tmp; - } - if(i & 1) - lpc_tmp[j] += lpc_tmp[j] * r; - - for(j = 0; j <= i; j++) - lpc[i][j] = -lpc_tmp[j]; - } - - return; -} - -/*Calculate reflection coefficients*/ -uint8_t compute_ref_coefs(int32_t *autoc,uint8_t max_order,int32_t *ref) -{ - int32_t i, j; - int32_t error; - int32_t gen[2][MAX_LPC_ORDER]; - uint8_t order_est; - - //Schurr recursion - for(i = 0; i < max_order; i++) - gen[0][i] = gen[1][i] = autoc[i+1]; - - error = autoc[0]; - ref[0] = ((int64_t)-gen[1][0]<<15) / error; - error += ((int64_t)gen[1][0] * ref[0] ) >> 15; - for(i = 1; i < max_order; i++) - { - for(j = 0; j < max_order - i; j++) - { - gen[1][j] = gen[1][j+1] + (int64_t)ref[i-1] * gen[0][j] >> 15; - gen[0][j] = (int64_t)gen[1][j+1] * ref[i-1] >> 15 + gen[0][j]; - } - ref[i] = ((int64_t)-gen[1][0]<<15) / error; - error += ((int64_t)gen[1][0] * ref[i])>>15; - } - - //Estimate optimal order using reflection coefficients - order_est = 1; - for(i = max_order - 1; i >= 0; i--) - { - if(abs(ref[i]) > 0.05*(1<<15)) - { - order_est = i+1; - break; - } - } - - return(order_est); -} - -static int32_t fastsqrt( int32_t x ) { - int64_t s = x; - x = 20000u; - x = ( x + s / x )/2; - x = ( x + s / x )/2; - x = ( x + s / x )/2; - x = ( x + s / x )/2; - return x; -} - -/*Quantize reflection coeffs*/ -int32_t qtz_ref_cof(int32_t *par,uint8_t ord,int32_t *q_ref) -{ - int i; - for( i = 0; i < ord; i++) - { - if(i == 0) - q_ref[i] = (( ((SQRT2 * fastsqrt(par[i] + 1)) >> 15) - (1<<15) )) >> 9; - } - - return(0); -} - -/*Dequantize reflection coefficients*/ -int32_t dqtz_ref_cof(const int32_t *q_ref,uint8_t ord,int32_t *ref) -{ - int i; - - if(ord <= 1) - { - ref[0] = 0; - return(0); - } - - for( i = 0; i < ord; i++) - { - if(i == 0) - ref[i] = lookup_1st_order_coeffs[q_ref[i] + 64]; - } - - return(0); -} - -/*Calculate residues from samples and lpc coefficients*/ -void calc_residue(const int32_t *samples,int64_t N,int16_t ord,int16_t Q,int64_t *coff,int32_t *residues) -{ - int64_t k, i; - int64_t corr; - int64_t y; - - corr = ((int64_t)1) << (Q - 1);//Correction term - - residues[0] = samples[0]; - for(k = 1; k <= ord; k++) - { - y = corr; - for(i = 1; i <= k; i++) - { - y += (int64_t)coff[i] * samples[k-i]; - if((k - i) == 0) - break; - } - residues[k] = samples[k] - (int32_t)(y >> Q); - } - - for(k = ord + 1; k < N; k++) - { - y = corr; - - for(i = 0; i <= ord; i++) - y += (int64_t)(coff[i] * samples[k-i]); - residues[k] = samples[k] - (int32_t)(y >> Q); - } - - return; -} - -/*Calculate samples from residues and lpc coefficients*/ -void calc_signal(const int32_t *residues,int64_t N,int16_t ord,int16_t Q,int64_t *coff,int32_t *samples) -{ - int64_t k, i; - int64_t corr; - int64_t y; - - corr = ((int64_t)1) << (Q - 1);//Correction term - - samples[0] = residues[0]; - for(k = 1; k <= ord; k++) - { - y = corr; - for(i = 1; i <= k; i++) - { - y -= (int64_t)(coff[i] * samples[k-i]); - if((k - i) == 0) - break; - } - samples[k] = residues[k] - (int32_t)(y >> Q); - } - - for(k = ord + 1; k < N; k++) - { - y = corr; - - for(i = 0; i <= ord; i++) - y -= (int64_t)(coff[i] * samples[k-i]); - samples[k] = residues[k] - (int32_t)(y >> Q); - } - - return; -} diff --git a/kitsune/codec/lpc.h b/kitsune/codec/lpc.h deleted file mode 100644 index 557a89a6..00000000 --- a/kitsune/codec/lpc.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _LPC_H_ -#define _LPC_H_ - -#define SQRT2 46340 -//1.4142135623730950488016887242096 -#define MAX_LPC_ORDER 1 - -int32_t check_if_constant(const int16_t *data,int32_t num_elements); -void auto_corr_fun(int32_t *x,int32_t N,int64_t k,int16_t norm,int32_t *rxx); -void levinson(int32_t *autoc,uint8_t max_order,int32_t *ref,int32_t lpc[][MAX_LPC_ORDER]); -uint8_t compute_ref_coefs(int32_t *autoc,uint8_t max_order,int32_t *ref); -int32_t qtz_ref_cof(int32_t *par,uint8_t ord,int32_t *q_ref); -int32_t dqtz_ref_cof(const int32_t *q_ref,uint8_t ord,int32_t *ref); -void calc_residue(const int32_t *samples,int64_t N,int16_t ord,int16_t Q,int64_t *coff,int32_t *residues); -void calc_signal(const int32_t *residues,int64_t N,int16_t ord,int16_t Q,int64_t *coff,int32_t *samples); - -#endif diff --git a/kitsune/codec_debug_config.h b/kitsune/codec_debug_config.h index 0dd5f5e9..f0658fd9 100644 --- a/kitsune/codec_debug_config.h +++ b/kitsune/codec_debug_config.h @@ -4,6 +4,4 @@ #define CODEC_ENABLE_MULTI_CHANNEL 1 // 0 -> Stereo, 1 -> 4 channels #define CODEC_LEFT_LATCH_FALLING 1 -#define AUDIO_FULL_DUPLEX 1 - #endif diff --git a/kitsune/commands.c b/kitsune/commands.c index 8dac2e99..35ee88e5 100644 --- a/kitsune/commands.c +++ b/kitsune/commands.c @@ -100,12 +100,9 @@ #include "filedownloadmanager.h" #include "tensor/keyword_net.h" +#include "octogram.h" -#define ONLY_AUDIO 0 - -#if (AUDIO_FULL_DUPLEX==1) #include "audiohelper.h" -#endif #define ONLY_MID 0 @@ -535,6 +532,8 @@ static bool _is_file_exists(char* path) } #include "hellofilesystem.h" uint8_t get_alpha_from_light(); +extern volatile int sys_volume; + void thread_alarm(void * unused) { int alarm_led_id = -1; while (1) { @@ -610,7 +609,7 @@ void thread_alarm(void * unused) { desc.stream = fs_stream_open_media(file_name,INT32_MAX); ustrncpy(desc.source_name, file_name, sizeof(desc.source_name)); desc.durationInSeconds = alarm.ring_duration_in_second; - desc.volume = 64; + desc.volume = sys_volume; desc.onFinished = thread_alarm_on_finished; desc.rate = AUDIO_SAMPLE_RATE; desc.context = &alarm_led_id; @@ -719,9 +718,33 @@ static light_data_t _light_data = {0}; xSemaphoreHandle i2c_smphr; +/** + * this returns the adjusted ambient light based on the combined + * sensors of r g b w als + * rgbw = 16bit + */ +typedef enum{ + RAW_LIGHT = 0, + LPF_LIGHT +}ambient_light_source; +int get_ambient_light_level(ambient_light_source source){ + int tmg[5] = {0}; + static int last_val; + get_rgb_prox(tmg+0, tmg+1, tmg+2, tmg+3, tmg+4); + int als = read_zopt(ZOPT_ALS); + int light = (als + tmg[0] * 10) / 2; + int val = (light * 3 + last_val * 7)/10; + last_val = val; + if(source == LPF_LIGHT){ + return val; + }else{ + return light; + } +// LOGF("(%d\t%d\t%d\t%d)(%d) = %d\r\n", tmg[0], tmg[1],tmg[2], tmg[3], als, val); +} uint8_t get_alpha_from_light() { - int adjust_max_light = 7366 / 4; + int adjust_max_light = 1000; int adjust; #if 0 @@ -740,7 +763,7 @@ uint8_t get_alpha_from_light() if( xTaskGetTickCount() - last_als > 1000 ) { last_als = xTaskGetTickCount(); - als = read_zopt( ZOPT_ALS ); + als = get_ambient_light_level(LPF_LIGHT); if( als > adjust_max_light ) { adjust = adjust_max_light; @@ -762,26 +785,28 @@ uint8_t get_alpha_from_light() static int _is_light_off() { static int last_light = -1; + static int now_light; static unsigned int last_light_time = 0; - const int light_off_threshold = 500; + const int light_off_threshold = 100; int ret = 0; xSemaphoreTakeRecursive(_light_data.light_smphr, portMAX_DELAY); + now_light = get_ambient_light_level(RAW_LIGHT); if(last_light != -1) { - int delta = last_light - _light_data.light; + int delta = last_light - now_light; if(xTaskGetTickCount() - last_light_time > 2000 && delta >= light_off_threshold - && _light_data.light < 100) + && now_light < 100) { - LOGI("light delta: %d, current %d, last %d\n", delta, _light_data.light, last_light); + LOGI("light delta: %d, current %d, last %d\n", delta, now_light, last_light); ret = 1; _light_data.light_mean =_light_data. light; //so the led alpha will be at the lights off level last_light_time = xTaskGetTickCount(); } } - last_light = _light_data.light; + last_light = now_light; xSemaphoreGiveRecursive(_light_data.light_smphr); return ret; @@ -955,7 +980,6 @@ void thread_fast_i2c_poll(void * unused) { LOGE("Thread fast i2c fail\n"); } - play_startup_sound(); vTaskDelayUntil(&now, delay); } } @@ -1144,7 +1168,7 @@ void sample_sensor_data(periodic_data* data) data->has_light_duration_ms = true; data->light_duration_ms = led_duration; - AudioOncePerMinuteData_t aud_data; + AudioEnergyStats_t aud_data; data->unix_time = get_time(); data->has_unix_time = true; { @@ -1221,7 +1245,7 @@ void sample_sensor_data(periodic_data* data) if (xSemaphoreTakeRecursive(_light_data.light_smphr, portMAX_DELAY)) { if(_light_data.light_cnt == 0) { - data->has_light_sensor = false; + data->has_light_sensor = false; // TODO This will will always be ovewritten by "data->has_light_sensor = true;" below }else{ _light_data.light_log_sum /= _light_data.light_cnt; // just be careful for devide by zero. _light_data.light_sf = (_light_data.light_mean << 8) / bitexp( _light_data.light_log_sum ); @@ -1760,9 +1784,14 @@ void launch_tasks() { hlo_audio_init(); // Create audio tasks for playback and record - xTaskCreate(AudioPlaybackTask,"playbackTask",10*1024/4,NULL,4,NULL); + xTaskCreate(AudioPlaybackTask,"playbackTask",4*1024/4,NULL,4,NULL); + + play_startup_sound(); + + xTaskCreate(AudioControlTask, "AudioControl", 7*1024 / 4, NULL, 2, NULL); + + - xTaskCreate(AudioControlTask, "AudioControl", 10*1024 / 4, NULL, 2, NULL); } int Cmd_boot(int argc, char *argv[]) { @@ -1940,13 +1969,16 @@ int Cmd_time_test(int argc, char * argv[]); int cmd_file_sync_upload(int argc, char *argv[]); extern volatile int ch; -extern volatile int sys_volume; int cmd_vol(int argc, char *argv[]) { set_system_volume( atoi(argv[1])) ; return 0; } +int cmd_get_vol(int argc, char* argv[]) { + LOGI("%d", get_system_volume()); + return 0; +} int cmd_ch(int argc, char *argv[]) { ch = atoi(argv[1]); @@ -1963,6 +1995,14 @@ int cmd_button(int argc, char *argv[]) { return 0; } int Cmd_readlight(int argc, char *argv[]); +int cmd_tap(int argc, char * argv[]){ + LOGI("User Tapped Sense\r\n"); + return 0; +} +int cmd_flipped(int argc, char * argv[]){ + LOGI("User Flipped Sense\r\n"); + return 0; +} // ============================================================================== // This is the table that holds the command names, implementing functions, and // brief description. @@ -1971,6 +2011,7 @@ tCmdLineEntry g_sCmdTable[] = { // { "cpu", Cmd_cpu, "Show CPU utilization" }, { "b", cmd_button, " " }, { "v", cmd_vol, " " }, + { "getv", cmd_get_vol, " " }, { "nnc", cmd_confidence, " " }, { "co", cmd_codec, " " }, @@ -2118,6 +2159,8 @@ tCmdLineEntry g_sCmdTable[] = { {"fs", cmd_file_sync_upload, ""}, {"nn",cmd_test_neural_net,""}, {"pn",cmd_audio_self_test,""}, + {"tap", cmd_tap, ""}, + {"flipped", cmd_flipped, ""}, { 0, 0, 0 } }; @@ -2233,6 +2276,7 @@ void vUARTTask(void *pvParameters) { init_tvoc(0x30); init_temp_sensor(); init_light_sensor(); + read_zopt(ZOPT_ALS); init_led_animation(); @@ -2274,7 +2318,6 @@ void vUARTTask(void *pvParameters) { xTaskCreate(top_board_task, "top_board_task", 1680 / 4, NULL, 3, NULL); xTaskCreate(thread_spi, "spiTask", 1536 / 4, NULL, 3, NULL); - #ifndef BUILD_SERVERS uart_logger_init(); xTaskCreate(uart_logger_task, "logger task", UART_LOGGER_THREAD_STACK_SIZE/ 4 , NULL, 1, NULL); @@ -2287,10 +2330,6 @@ void vUARTTask(void *pvParameters) { UARTprintf("*"); start_top_boot_watcher(); - /******************************************************************************* - * AUDIO INIT END - ******************************************************************************** - */ sl_WlanPolicySet(SL_WLAN_POLICY_CONNECTION, SL_WLAN_CONNECTION_POLICY(1, 0, 0, 0), NULL, 0); #ifndef DEMO diff --git a/kitsune/endpoints.h b/kitsune/endpoints.h index 4fc6d0e1..72f03124 100644 --- a/kitsune/endpoints.h +++ b/kitsune/endpoints.h @@ -24,7 +24,7 @@ char * get_speech_server(void); #define PROD_SPEECH_SERVER "speech.hello.is" #define DEV_SPEECH_SERVER "dev-speech.hello.is" -#define SPEECH_ENDPOINT "/demo/upload/audio" +#define SPEECH_ENDPOINT "/v2/upload/audio" #define MESSEJI_ENDPOINT "/receive" diff --git a/kitsune/fatfs_cmd.c b/kitsune/fatfs_cmd.c index 475e3c13..cb2b5a09 100644 --- a/kitsune/fatfs_cmd.c +++ b/kitsune/fatfs_cmd.c @@ -923,9 +923,9 @@ void boot_commit_ota() { DISP("\r\n-----------------------\r\n"); LOGI("Booted in testing mode\r\n"); DISP("\r\n-----------------------\r\n"); - if( !verify_top_update() ){ + if( 0 == verify_top_update() ){ LOGI("Updating top board\r\n"); - send_top("dfu", strlen("dfu")); + activate_top_ota(); if(wait_for_top_boot(60000)){ LOGI("Top board update success\r\n"); //delete update on success @@ -1287,6 +1287,9 @@ int sf_sha1_verify(const char * sha_truth, const char * serial_file_path){ } hlo_stream_close(fs); SHA1_Final(sha, &sha1ctx); + }else{ + LOGI("%s does not exist/error!\r\n", serial_file_path); + return -1; } //compare if (memcmp(sha, sha_truth, SHA1_SIZE) != 0) { diff --git a/kitsune/fft.c b/kitsune/fft.c index 9f37166b..b9c4d040 100644 --- a/kitsune/fft.c +++ b/kitsune/fft.c @@ -236,6 +236,7 @@ int fftr(int16_t f[], int32_t m) f[i] = tt; } fft(fi, fr, m-1); + return 0; } //requires 2N memory... for now diff --git a/kitsune/gesture.c b/kitsune/gesture.c index dd133eed..3dcc8cc2 100644 --- a/kitsune/gesture.c +++ b/kitsune/gesture.c @@ -10,7 +10,7 @@ /* how much delta does it take to activate the fsm over noise floor */ /* set to 2x observed max at idle on DVT 1p5 */ -#define DETECTION_THRESH 100 +#define DETECTION_THRESH 200 /* minimal frames require for the wave gesture */ #define GESTURE_WAVE_MULTIPLIER (1) @@ -89,8 +89,18 @@ static gesture_t _fsm(int in){ case GFSM_IDLE_FORREALS: //any edge triggers edge up state if( exceeded > 0 ){ - LOGI("->1\r\n"); + LOGI("->1 %d\r\n", in); _transition_state(GFSM_LEVEL); +#if 1 + LOGF("Gesture: WAVE\r\n"); + analytics_event( "{gesture: wave}" ); + if(xSemaphoreTake(self.gesture_count_semaphore, 100) == pdTRUE) + { + self.wave_count += 1; + xSemaphoreGive(self.gesture_count_semaphore); + } + ret = GESTURE_WAVE; +#endif } break; case GFSM_LEVEL: @@ -107,6 +117,7 @@ static gesture_t _fsm(int in){ ret = GESTURE_HOLD; } else if (_hasWave()) { if (_hasWave()) { +#if 0 LOGF("Gesture: WAVE\r\n"); analytics_event( "{gesture: wave}" ); if(xSemaphoreTake(self.gesture_count_semaphore, 100) == pdTRUE) @@ -115,6 +126,7 @@ static gesture_t _fsm(int in){ xSemaphoreGive(self.gesture_count_semaphore); } ret = GESTURE_WAVE; +#endif } _transition_state(GFSM_IDLE); LOGI("\r\n"); @@ -146,7 +158,6 @@ void gesture_init(){ self.last_pause = 0; self.gesture_count_semaphore = xSemaphoreCreateMutex(); } - gesture_t gesture_input(int prox){ if( !self.output_gesture ) { _fsm_reset(); diff --git a/kitsune/hlo_audio.c b/kitsune/hlo_audio.c index 1dab0022..b895cdb1 100644 --- a/kitsune/hlo_audio.c +++ b/kitsune/hlo_audio.c @@ -229,6 +229,7 @@ static void _do_lights(void * ctx, const void * buf, size_t size) { int16_t * samples = (int16_t *)buf; size /= sizeof(int16_t); +#if 0 for(i = 0; i < size; i++){ stream->eng += abs(samples[i]); @@ -262,6 +263,9 @@ static void _do_lights(void * ctx, const void * buf, size_t size) { stream->eng = 0; } } +#else + //set_modulation_intensity( get_alpha_from_light() ); +#endif } static int _write_light(void * ctx, const void * buf, size_t size) { @@ -306,7 +310,7 @@ hlo_stream_t * hlo_light_stream( hlo_stream_t * base, bool start){ if( start ) { DISP("open light\n") ; - set_modulation_intensity( 253 ); + set_modulation_intensity( get_alpha_from_light() ); play_modulation(140,29,237,100,0); stream->close_lights = false; stream->lp = 2000; diff --git a/kitsune/hlo_audio_tools.c b/kitsune/hlo_audio_tools.c index a46b7247..38c1cf3d 100644 --- a/kitsune/hlo_audio_tools.c +++ b/kitsune/hlo_audio_tools.c @@ -34,34 +34,35 @@ AudioState get_audio_state(); #include "audiofeatures.h" #include "tensor/tinytensor_math_defs.h" -#define OKAY_SENSE_THRESHOLD TOFIX(0.95) -#define OKAY_SENSE_MIN_DURATION 5 +#define OKAY_SENSE_THRESHOLD TOFIX(0.9) +#define OKAY_SENSE_MIN_DURATION 3 -#define SNOOZE_THRESHOLD TOFIX(0.60) +#define SNOOZE_THRESHOLD TOFIX(0.70) #define SNOOZE_MIN_DURATION 1 -#define STOP_THRESHOLD TOFIX(0.40) -#define STOP_MIN_DURATION 1 +#define STOP_THRESHOLD TOFIX(0.90) +#define STOP_MIN_DURATION 3 static xSemaphoreHandle _statsMutex = NULL; -static AudioOncePerMinuteData_t _stats; +static AudioEnergyStats_t _stats; int audio_sig_stop = 0; -static void StatsCallback(const AudioOncePerMinuteData_t * pdata) { +static void StatsCallback(const AudioEnergyStats_t * pdata) { xSemaphoreTake(_statsMutex,portMAX_DELAY); if(pdata->num_disturbances){ - LOGI("audio disturbance: %d, background=%d, peak=%d, samples = %d\r",pdata->num_disturbances, pdata->peak_background_energy, _stats.peak_energy , _stats.num_samples); + LOGI("audio disturbance:ms=%d,bg=%d,peak=%d,peak_for_minute=%d,samples=%d\r\n",_stats.disturbance_time_count, pdata->peak_background_energy,pdata->peak_energy, _stats.peak_energy , _stats.num_samples); LOGI("\n"); } _stats.num_disturbances += pdata->num_disturbances; + _stats.disturbance_time_count += pdata->disturbance_time_count; _stats.num_samples++; - if (pdata->peak_background_energy > _stats.peak_background_energy) { - _stats.peak_background_energy = pdata->peak_background_energy; - } + if (pdata->peak_background_energy > _stats.peak_background_energy) { + _stats.peak_background_energy = pdata->peak_background_energy; + } if (pdata->peak_energy > _stats.peak_energy) { _stats.peak_energy = pdata->peak_energy; @@ -69,15 +70,17 @@ static void StatsCallback(const AudioOncePerMinuteData_t * pdata) { _stats.isValid = 1; xSemaphoreGive(_statsMutex); } -void AudioTask_DumpOncePerMinuteStats(AudioOncePerMinuteData_t * pdata) { +void AudioTask_DumpOncePerMinuteStats(AudioEnergyStats_t * pdata) { if(!_statsMutex){ _statsMutex = xSemaphoreCreateMutex(); assert(_statsMutex); } xSemaphoreTake(_statsMutex,portMAX_DELAY); - memcpy(pdata,&_stats,sizeof(AudioOncePerMinuteData_t)); - pdata->peak_background_energy/=pdata->num_samples; + + //copy and reset + memcpy(pdata,&_stats,sizeof(AudioEnergyStats_t)); memset(&_stats,0,sizeof(_stats)); + xSemaphoreGive(_statsMutex); } ////------------------------------------------- @@ -170,7 +173,7 @@ int hlo_filter_throughput_test(hlo_stream_t * input, hlo_stream_t * output, void ////------------------------------------------- //octogram sample app #include "octogram.h" -#define PROCESSOR_BUFFER_SIZE ((AUDIO_FFT_SIZE)*3*2) +#define PROCESSOR_BUFFER_SIZE ((OCTOGRAM_FFT_SIZE)*3*2) #define OCTOGRAM_DURATION 10 int hlo_filter_octogram(hlo_stream_t * input, hlo_stream_t * output, void * ctx, hlo_stream_signal signal){ Octogram_t octogramdata = {0}; @@ -182,7 +185,7 @@ int hlo_filter_octogram(hlo_stream_t * input, hlo_stream_t * output, void * ctx, while( (ret = hlo_stream_transfer_all(FROM_STREAM,input,(uint8_t*)samples,PROCESSOR_BUFFER_SIZE,4)) > 0){ //convert from 48K to 16K for(i = 0; i < 256; i++){ - int32_t sum = samples[i] + samples[AUDIO_FFT_SIZE+i] + samples[(2*AUDIO_FFT_SIZE)+i]; + int32_t sum = samples[i] + samples[OCTOGRAM_FFT_SIZE+i] + samples[(2*OCTOGRAM_FFT_SIZE)+i]; samples[i] = (int16_t)(sum / 3); } Octogram_Update(&octogramdata,samples); @@ -218,7 +221,7 @@ extern bool _decode_string_field(pb_istream_t *stream, const pb_field_t *field, #include "tensor/keyword_net.h" typedef struct{ hlo_stream_t * base; - speech_data speech_pb; + SpeechRequest speech_pb; uint8_t threshold; uint16_t reserved; uint32_t timeout; @@ -235,6 +238,12 @@ static void _voice_finish_keyword(void * ctx, Keyword_t keyword, int16_t value){ p->speech_pb.has_version = true; p->speech_pb.version = KIT_VER; + p->speech_pb.has_eq = true; + p->speech_pb.eq = Equalizer_NONE; + p->speech_pb.has_response = true; + p->speech_pb.response = AudioFormat_MP3; + p->speech_pb.has_sampling_rate = true; + p->speech_pb.sampling_rate = AUDIO_SAMPLE_RATE/2; p->speech_pb.has_confidence = true; p->speech_pb.confidence = value >> 5; // I think server is expecting q7 @@ -245,13 +254,13 @@ static void _voice_finish_keyword(void * ctx, Keyword_t keyword, int16_t value){ switch (keyword ) { case okay_sense: LOGI("OKAY SENSE\r\n"); - p->speech_pb.word = keyword_OK_SENSE; + p->speech_pb.word = Keyword_OK_SENSE; break; case snooze: - p->speech_pb.word = keyword_SNOOZE; + p->speech_pb.word = Keyword_SNOOZE; break; case stop: - p->speech_pb.word = keyword_STOP; + p->speech_pb.word = Keyword_STOP; break; } } @@ -330,7 +339,7 @@ int hlo_filter_voice_command(hlo_stream_t * input, hlo_stream_t * output, void * uint32_t begin = xTaskGetTickCount(); uint32_t speech_detected_time; - hlo_stream_t * wwbuf = hlo_lossless_init_chunkbuf(10*1024); + hlo_stream_t * wwbuf = hlo_lossless_init_chunkbuf(20*1024); while( (ret = hlo_stream_transfer_all(FROM_STREAM, input, (uint8_t*)samples, NUM_SAMPLES_TO_RUN_FFT*2, 4)) > 0 ){ //net always gets samples @@ -338,15 +347,17 @@ int hlo_filter_voice_command(hlo_stream_t * input, hlo_stream_t * output, void * keyword_net_add_audio_samples(samples,ret/sizeof(int16_t)); } - if( nn_ctx.speech_pb.has_word ) { + if( nn_ctx.speech_pb.has_word && nn_ctx.speech_pb.word == Keyword_OK_SENSE) { if( !light_open ) { light_sensor_power(LOW_POWER); keyword_net_pause_net_operation(); + stop_led_animation(2,20); input = hlo_light_stream( input,true ); send_str = hlo_stream_bw_limited( send_str, AUDIO_NET_RATE/8, 5000); light_open = true; - hlo_pb_encode(send_str, speech_data_fields, &nn_ctx.speech_pb); + hlo_pb_encode(send_str, SpeechRequest_fields, &nn_ctx.speech_pb); + speech_detected_time = xTaskGetTickCount(); ret = hlo_lossless_dump_chunkbuf( wwbuf, send_str ); @@ -380,7 +391,9 @@ int hlo_filter_voice_command(hlo_stream_t * input, hlo_stream_t * output, void * light_sensor_power(HIGH_POWER); if (ret < 0) { - stop_led_animation(0, 33); + if( ret != HLO_STREAM_EAGAIN ) { + stop_led_animation(2, 33); + } if (ret == HLO_STREAM_ERROR) { play_led_animation_solid(LED_MAX, LED_MAX, 0, 0, 1, 18, 1); } @@ -412,6 +425,7 @@ int hlo_filter_voice_command(hlo_stream_t * input, hlo_stream_t * output, void * LOGI("\r\n===========\r\n"); } + hlo_stream_close(send_str); keyword_net_deinitialize(); @@ -759,7 +773,7 @@ int Cmd_stream_transfer(int argc, char * argv[]){ if(argc >= 4){ f = _filter_from_string(argv[3]); } -#if 0 +#if 1 hlo_stream_t * in = open_stream_from_path(argv[1],1); #else hlo_stream_t * in = open_stream_from_path(argv[1],2); // TODO DKH diff --git a/kitsune/hlo_stream.c b/kitsune/hlo_stream.c index 0b226101..11c5fb58 100644 --- a/kitsune/hlo_stream.c +++ b/kitsune/hlo_stream.c @@ -199,7 +199,7 @@ static int circ_write(void * ctx, const void * buf, size_t size){ uint8_t dummy; while(circ->filled > circ->capacity - size - 1){ - circ_read_byte(circ, dummy); + circ_read_byte(circ, &dummy); } int written = 0; while(size && circ->filled < circ->capacity){ diff --git a/kitsune/i2c_cmd.c b/kitsune/i2c_cmd.c index fa2acb81..ca846145 100644 --- a/kitsune/i2c_cmd.c +++ b/kitsune/i2c_cmd.c @@ -442,16 +442,16 @@ int get_temp_press_hum(int32_t * temp, uint32_t * press, uint32_t * hum) { xSemaphoreGiveRecursive(i2c_smphr); + temp_raw = (b[3] << 16) | (b[4]<<8) | (b[5]); + temp_raw >>= 4; + *temp = BME280_compensate_T_int32(temp_raw); + DBG_BME("%x %x %x %d %d\n", b[3],b[4],b[5], temp_raw, *temp); + press_raw = (b[0] << 16) | (b[1]<<8) | (b[2]); press_raw >>= 4; *press = BME280_compensate_P_int64(press_raw); DBG_BME("%x %x %x %d %d\n", b[0],b[1],b[2], press_raw, *press); - temp_raw = (b[3] << 16) | (b[4]<<8) | (b[5]); - temp_raw >>= 4; - *temp = BME280_compensate_T_int32(temp_raw); - DBG_BME("%x %x %x %d %d\n", b[0],b[1],b[2], temp_raw, *temp); - hum_raw = (b[6]<<8) | (b[7]); *hum = bme280_compensate_H_int32(hum_raw); @@ -672,7 +672,7 @@ int light_sensor_power(light_power_mode power_state) { b[0] = 0x8E; if( power_state == HIGH_POWER ) { resume_gestures(); - b[1] = 0xc0; + b[1] = 0xcf; } else { pause_gestures(); b[1] = 0; @@ -696,7 +696,7 @@ int init_light_sensor() assert(xSemaphoreTakeRecursive(i2c_smphr, 1000)); b[0] = 0x80; - b[1] = 0b1000111; //enable gesture/prox/als/power + b[1] = 0b0000111; //enable prox/als/power b[2] = 249; //20ms integration b[3] = 35; //100ms prox time b[4] = 249; //20ms als time @@ -710,7 +710,7 @@ int init_light_sensor() //max pulse length, number of pluses b[0] = 0x8E; - b[1] = 0xC0; + b[1] = 0xCF; (I2C_IF_Write(0x39, b, 2, 1)); //gain and power @@ -782,7 +782,7 @@ int get_ir( int * ir ) { (I2C_IF_Write(0x39, b, 2, 1)); vTaskDelay(110); get_rgb_prox( &w, &r, &g, &bl, &p ); - *ir = w+r+g+bl; + *ir = (r+g+bl-w)/2; b[0] = 0xAB; b[1] = 0x00; @@ -912,18 +912,20 @@ static void codec_sw_reset(void); * On the codec, this gain has 117 levels between 0db to -78.3db * The input v to the function varies from 0-64. */ -volatile int sys_volume = 64; +volatile int sys_volume = 60; #define VOL_LOC "/hello/vol" int get_system_volume() { if( fs_get(VOL_LOC, &sys_volume, sizeof(sys_volume), NULL) < 0 ) { - sys_volume = 64; + sys_volume = 60; } + + return sys_volume; } int32_t set_system_volume(int new_volume) { if( new_volume != sys_volume ) { sys_volume = new_volume; - fs_save(VOL_LOC, sys_volume, sizeof(sys_volume)); + fs_save(VOL_LOC, &sys_volume, sizeof(sys_volume)); } return set_volume(new_volume, portMAX_DELAY); } @@ -1120,7 +1122,7 @@ void codec_unmute_spkr(void) if( xSemaphoreTakeRecursive(i2c_smphr, 100)) { cmd[0] = 48; - cmd[1] = (SPK_VOLUME_18dB << 4) | (1 << 0); + cmd[1] = (SPK_VOLUME_18dB << 4); I2C_IF_Write(Codec_addr, cmd, 2, send_stop); xSemaphoreGiveRecursive(i2c_smphr); diff --git a/kitsune/main/ccs/.cproject b/kitsune/main/ccs/.cproject index 82215328..d29d377e 100644 --- a/kitsune/main/ccs/.cproject +++ b/kitsune/main/ccs/.cproject @@ -186,14 +186,6 @@ - - - - - - - -