Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions inc/EmojiRecogniser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

#ifndef EMOJI_RECOGNISER_H
#define EMOJI_RECOGNISER_H

/*
*
* The emoji recogniser is a subclass of sound recogniser that defines
* the actual samples for the emoji sounds. They are just parts of the
* emoji sounds that can be recognised: remain quite consistent across
* multiple plays of the sound.
*
*
* Example
*
* Taking the happy sound as an example, there are a few constants defined:
*
* happy_sequences the number of sequences in the happy sound
*
* happy_max_deviations the maximum number of deviations in the
* sound - i.e. a deviation is considered
* a data point that is more than the allowed
* threshold off the sampled frequency
*
* happy_samples a 3-dimensional array with the sampled sound:
* - the first dimension is the different
* sequences
* - the second is the samples in each sequence
* - the third is the data points in each sample
* of each sequence
*
* happy_thresholds an array with the thresholds for each of the
* sequences
*
* happy_deviations an array with the maximum deviations for each
* sequence
*
* happy_nr_samples an array with the number of samples in each
* sequence
*
* All these are packaged in a Sound struct.
*/

#include "MicroBitSoundRecogniser.h"

class EmojiRecogniser : public MicroBitSoundRecogniser
{
void addHappySound();
void addHelloSound();
void addSadSound();
void addSoaringSound();
void addTwinkleSound();

public:
EmojiRecogniser(MicroBitAudioProcessor& processor);
};

#endif
147 changes: 129 additions & 18 deletions inc/MicroBitAudioProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,142 @@ DEALINGS IN THE SOFTWARE.
#ifndef MICROBIT_AUDIO_PROCESSOR_H
#define MICROBIT_AUDIO_PROCESSOR_H

#define MIC_SAMPLE_RATE (11 * 1024)
#define AUDIO_SAMPLES_NUMBER 1024
/*
* Provides the fundamental frequencies in the microphone data.
*
* It takes in the microphone data (sampled at MIC_SAMPLE_RATE Hz
* which is ~11000 Hz now) and produces AudioFrameAnalysis data.
*
*/

// Default configuration values
#define MIC_SAMPLE_RATE (1000000 / MIC_SAMPLE_DELTA)
#define DEFAULT_AUDIO_SAMPLES_NUMBER 512
#define EMOJI_AUDIO_SAMPLES_NUMBER 512
#define MORSE_AUDIO_SAMPLES_NUMBER 128

#define RECOGNITION_START_FREQ 1700
#define RECOGNITION_END_FREQ 5400

#define ANALYSIS_STD_MULT_THRESHOLD 3
#define ANALYSIS_STD_THRESHOLD 50
#define ANALYSIS_MEAN_THRESHOLD 0

class MicroBitAudioProcessor : public DataSink
#define MAXIMUM_NUMBER_OF_FREQUENCIES 3
#define SIMILAR_FREQ_THRESHOLD 100

class MicroBitAudioProcessor : public DataSink, public DataSource
{
DataSource &audiostream;
int zeroOffset; // unsigned value that is the best effort guess of the zero point of the data source
int divisor; // Used for LINEAR modes
arm_rfft_fast_instance_f32 fft_instance;
float *buf;
float *output;
float *mag;
uint16_t position;
bool recording;
float rec[AUDIO_SAMPLES_NUMBER * 2];
int lastFreq;
public:

/*
* An AudioFrameAnalysis has the fundamental frequencies of a
* frame - maximum MAXIMUM_NUMBER_OF_FREQUENCIES and ordered
* from the most likely to the least.
*/
struct AudioFrameAnalysis {
uint8_t size;
uint16_t buf[MAXIMUM_NUMBER_OF_FREQUENCIES];
};

private:

DataSource &audiostream; // the stream of data to analyse
DataSink *recogniser; // the recogniser the frequencies should be send to
uint16_t audio_samples_number; // the number of samples to collect before analysing a frame
arm_rfft_fast_instance_f32 fft_instance; // the instance of CMSIS fft that is used to run fft
float *buf; // the buffer to store the incoming data
float *fft_output; // an array to store the result of the fft
float *mag; // an array to store the magnitudes of the frequencies

uint16_t buf_len; // the length of the incoming buffer
bool recording; // whether it should analyse the data or be idle

AudioFrameAnalysis output; // the result of the analysis

/*
* Converts from frequency to the index in the array.
*
* @param freq a frequency in the range 0 - 5000 Hz.
*
* @return the index to the frequency bucket freq is in
* as it comes out of the fft
*/
uint16_t frequencyToIndex(int freq);

/*
* Converts from the index in the array to frequency.
*
* @param index a index in the range 0 - audio_samples_number / 2.
*
* @return the avg frequency in the bucket
*/
float32_t indexToFrequency(int index);

public:
MicroBitAudioProcessor(DataSource& source);

/*
* Constructor.
*
* Initialize the MicroBitAduioProcessor.
*/
MicroBitAudioProcessor(DataSource& source, uint16_t audio_samples_number = DEFAULT_AUDIO_SAMPLES_NUMBER);

/*
* Destructor.
*
* Deallocates all the memory allocated dynamically.
*/
~MicroBitAudioProcessor();

/*
* A callback for when the data is ready.
*
* Analyses the data when enough of it comes in, using
* the following algorithm:
*
* The audio processor accumulates microphone data as it comes
* in and after getting audio_samples_number of them it process
* the frame.
*
* It transforms the date from time domain to frequency domain
* using the CMSIS fft.
*
* If the mean of the magnitudes of frequnecies is lower than
* ANALYSIS_MEAN_THRESHOLD or the standard deviation (std) is
* lower than ANALYSIS_STD_THRESHOLD then the frame is considered
* silence - no fundamental frequency.
*
* It then filters out the frequencies that have a magnitude lower
* than the mean + ANALYSIS_STD_MULT_THRESHOLD * std. This ensures
* that only outlier frequencies are being considered.
*
* It then filters out the neighbour frequencies around the peaks.
*
* Some of these operations are implemented together to optimize the
* algorithm.
*/
virtual int pullRequest();
int getFrequency();
int setDivisor(int d);

/*
* Allow out downstream component to register itself with us
*/
void connect(DataSink *downstream);

/*
* Provides the next available data to the downstream caller.
*/
virtual ManagedBuffer pull();

/*
* Starts recording and analysing.
*/
void startRecording();
void stopRecording(MicroBit& uBit);

/*
* Stops from recording and analysing.
*/
void stopRecording();
};

#endif
52 changes: 52 additions & 0 deletions inc/MicroBitMorseCodeRecogniser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

#ifndef MICROBIT_MORSE_CODE_RECOGNISER_H
#define MICROBIT_MORSE_CODE_RECOGNISER_H

#include "DataStream.h"
#include "MicroBitAudioProcessor.h"
#include "arm_math.h"

#define DETECTION_THRESHOLD 150
#define MORSE_FRAME_TRUE_RATE_THRESHOLD 0.8
#define MAX_TIME_UNIT 500

class MicroBitMorseCodeRecogniser : public DataSink
{
MicroBitAudioProcessor& audio_proceesor;
MicroBit& uBit;

uint16_t timeUnit;
uint16_t frequency;

bool analysing;
bool syncronised;
unsigned int pauses;

bool buffer[2 * MAX_TIME_UNIT];
bool normalised_buffer[6];
uint16_t buffer_len;
uint16_t normalised_buffer_len;

void (*callback)(ManagedString) = NULL;

void processFrame(MicroBitAudioProcessor::AudioFrameAnalysis* frame);

bool recogniseLastMorseFrame(uint16_t to, uint16_t threshold );

public:
MicroBitMorseCodeRecogniser(MicroBitAudioProcessor& processor, MicroBit& uBit, uint16_t freq, uint16_t timeUnit) ;

~MicroBitMorseCodeRecogniser();

virtual int pullRequest();

MicroBitAudioProcessor* getAudioProcessor();

void setCallback (void (*_callback)(ManagedString));
void startAnalisying(void (*_callback)(ManagedString));
void stopAnalisying();

};


#endif
53 changes: 53 additions & 0 deletions inc/MicroBitMorseCommunicator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
The MIT License (MIT)
Copyright (c) 2020 Arm Limited.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#include "MicroBit.h"

#define DEFAULT_DURATION 500
#define DEFAULT_FREQUENCY 2000
#define DEFAULT_RANDOMNESS 0

class MicroBitMorseCommunicator
{
private:

int duration;
int frequency;
int randomness;
MicroBit* uBit;

ManagedString dotFrame;
ManagedString dashFrame;

void createFrames();
void play(Symbol s);


public:
MicroBitMorseCommunicator(MicroBit* bit);
~MicroBitMorseCommunicator();
void send(MicroBitMorseMessage* mess);

void set_duration(int d);
void set_frequency(int f); // this could be replaced by set_channel eventually
void set_randomness(int r); // this will probably be removed once we decide how much we want


};
Loading