Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add sample recording and playback capabilities #5

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
77 changes: 77 additions & 0 deletions inc/drivers/CalliopeMicrophone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
The MIT License (MIT)

Copyright (c) 2017 Calliope gGmbH
This software is provided by utz (M. Neidel) by arrangement with Calliope gGmbH.

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.
*/


#ifdef TARGET_NRF51_CALLIOPE

#ifndef CALLIOPE_MICROPHONE_H
#define CALLIOPE_MICROPHONE_H

#include "mbed.h"
#include "MicroBitIO.h"
#include "MicroBitComponent.h"


#define CALLIOPE_DEFAULT_SAMPLE_RATE 8000 //default sample rate for PWM sampling
#define CALLIOPE_MAX_SAMPLE_RATE 11025 //max sample rate, limited by sample loop exec time
#define CALLIOPE_MIN_SAMPLE_RATE 1 //min sample rate
#define CALLIOPE_MIN_SAMPLE_BUFFER_SIZE 1 //min sample buffer size
#define CALLIOPE_MIC_DEFAULT_SENSITIVITY 48 //mic sensitivity level (0..77)
#define CALLIOPE_MIC_MAX_SENSITIVITY 77
#define CALLIOPE_MIC_BASE_LEVEL 518 //mic input null level

class CalliopeMicrophone : public MicroBitComponent
{
public:
//constructor
CalliopeMicrophone();

//destructor
~CalliopeMicrophone();

//function to initialize recording
static void recordSample(uint8_t* buffer, int16_t len,
uint16_t sensitivity = CALLIOPE_MIC_DEFAULT_SENSITIVITY, int16_t sample_rate = CALLIOPE_DEFAULT_SAMPLE_RATE);
//function to stop/abort recording
static void stopRecording();
//interrupt service, do not call directly!
static void updateInput();
//function check recording status
static bool isRecording();

private:
static uint8_t* rec_buffer;
static int16_t rec_len;
static int16_t rec_pos;
static uint8_t pwm_tick;
static uint16_t upper_threshold;
static uint16_t lower_threshold;
static AnalogIn micpin;
static mbed::Ticker rec_ticker;
static bool active;
};

#endif
#endif // TARGET_NRF51_CALLIOPE
24 changes: 22 additions & 2 deletions inc/drivers/CalliopeSoundMotor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ The MIT License (MIT)

Copyright (c) 2016 Calliope GbR
This software is provided by DELTA Systems (Georg Sommer) - Thomas Kern
und Björn Eberhardt GbR by arrangement with Calliope GbR.
und Björn Eberhardt GbR by arrangement with Calliope GbR. Modifications
and additional PWM sample driver by Michael Neidel.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -51,6 +52,12 @@ DEALINGS IN THE SOFTWARE.
#define CALLIOPE_MAX_FREQUENCY_HZ_S 20000 //max human audible frequency
#define CALLIOPE_BOARD_FREQUENCY 16000000

//constants for sound sampling
#define CALLIOPE_DEFAULT_SAMPLE_RATE 8000 //default sample rate for PWM samples
#define CALLIOPE_MAX_SAMPLE_RATE 11025 //max sample rate (limited by sampling loop exec time)
#define CALLIOPE_MIN_SAMPLE_RATE 1 //min sample rate


class CalliopeSoundMotor : public MicroBitComponent
{
//current settings
Expand All @@ -62,9 +69,17 @@ class CalliopeSoundMotor : public MicroBitComponent
static uint16_t frequency_sound_hz;
static bool silent_mode;

//current use of the controller -> 0: off, 1: motor use, 2: dual motor use, 3: sound use
//current use of the controller -> 0: off, 1: motor use, 2: dual motor use, 3: sound use, 4: pwm sample playback
static uint8_t mode;

//sample playback settings
static uint8_t* sample_buffer;
static uint16_t sample_len;
static uint16_t sample_pos;
static uint8_t sample_period_tick;
static bool sample_playing;
static mbed::Ticker sample_ticker;

public:
//constructor
CalliopeSoundMotor();
Expand Down Expand Up @@ -92,6 +107,11 @@ class CalliopeSoundMotor : public MicroBitComponent
void soundOn(uint16_t frequency_hz = frequency_sound_hz);
void setSoundSilentMode(bool on_off);
void soundOff();

//functions for sample playback
static void playSample(uint8_t* buffer, uint16_t len, int16_t sample_rate = CALLIOPE_DEFAULT_SAMPLE_RATE);
static void stopSamplePlayback();
static void updateSampleOutput();

//check fucntions
bool motorIsOn();
Expand Down
3 changes: 1 addition & 2 deletions source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
"drivers/MicroBitAccelerometer-bmx.cpp"
"drivers/MicroBitButton.cpp"
"drivers/MicroBitCompass.cpp"
"drivers/MicroBitCompass-bmx.cpp"
"drivers/MicroBitCompassCalibrator.cpp"
"drivers/MicroBitDisplay.cpp"
"drivers/MicroBitI2C.cpp"
Expand All @@ -36,7 +35,6 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
"drivers/MicroBitMessageBus.cpp"
"drivers/MicroBitMultiButton.cpp"
"drivers/MicroBitPin.cpp"
"drivers/MicroBitQuadratureDecoder.cpp"
"drivers/MicroBitRadio.cpp"
"drivers/MicroBitRadioDatagram.cpp"
"drivers/MicroBitRadioEvent.cpp"
Expand All @@ -47,6 +45,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
"drivers/MicroBitFlash.cpp"
"drivers/MicroBitFile.cpp"
"drivers/MicroBitFileSystem.cpp"
"drivers/CalliopeMicrophone.cpp"
"drivers/CalliopeSoundMotor.cpp"
"drivers/CalliopeRGB.cpp"

Expand Down
126 changes: 126 additions & 0 deletions source/drivers/CalliopeMicrophone.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
The MIT License (MIT)

Copyright (c) 2017 Calliope gGmbH
This software is provided by utz (M. Neidel) by arrangement with Calliope gGmbH.

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.
*/


#ifdef TARGET_NRF51_CALLIOPE

#include "CalliopeMicrophone.h"
#include "MicroBitSystemTimer.h"
#include "MicroBitPin.h"

//define static members
uint8_t* CalliopeMicrophone::rec_buffer;
int16_t CalliopeMicrophone::rec_len;
int16_t CalliopeMicrophone::rec_pos;
uint8_t CalliopeMicrophone::pwm_tick;
uint16_t CalliopeMicrophone::upper_threshold;
uint16_t CalliopeMicrophone::lower_threshold;
AnalogIn CalliopeMicrophone::micpin(MIC);
mbed::Ticker CalliopeMicrophone::rec_ticker;
bool CalliopeMicrophone::active = false;

//constructor
CalliopeMicrophone::CalliopeMicrophone()
{
system_timer_add_component(this);
}


//destructor
CalliopeMicrophone::~CalliopeMicrophone()
{
system_timer_remove_component(this);
}


//PWM sampling function: records sound from microphone and converts to 1-bit PWM data until buffer is full
void CalliopeMicrophone::recordSample(uint8_t* buffer, int16_t len, uint16_t sensitivity, int16_t sample_rate)
{
//refuse to run if already recording
if (active) return;

//return on invalid parameters
if (len < CALLIOPE_MIN_SAMPLE_BUFFER_SIZE || sample_rate > CALLIOPE_MAX_SAMPLE_RATE
|| sample_rate < CALLIOPE_MIN_SAMPLE_RATE || sensitivity > CALLIOPE_MIC_MAX_SENSITIVITY) return;

//set recording mode
active = true;

//initialize recording parameters
rec_buffer = buffer;
rec_len = len;
rec_pos = 0;
pwm_tick = 1;
upper_threshold = CALLIOPE_MIC_BASE_LEVEL + (80 - sensitivity);
lower_threshold = CALLIOPE_MIC_BASE_LEVEL - (80 - sensitivity);

//set up interrupt service
rec_ticker.attach_us(&updateInput, static_cast<timestamp_t>(1000000 / sample_rate));
}


void CalliopeMicrophone::stopRecording() {

//do nothing if not recording
if (!active) return;

//disable interrupt
rec_ticker.detach();

//set recording status
active = false;
}

//interrupt service routine for sample recording - do not call directly!
void CalliopeMicrophone::updateInput()
{
//stop recording if buffer is full
if (rec_pos >= rec_len)
{
stopRecording();
return;
}

//read value analog input
uint16_t val = micpin.read_u16();

//update pwm period counter and write to buffer if input crossed threshold or counter wrapped
if (pwm_tick && ((!(rec_pos & 1) && val > lower_threshold)
|| ((rec_pos & 1) && val < upper_threshold))) ++pwm_tick;
else
{
rec_buffer[rec_pos] = pwm_tick;
pwm_tick = 1;
++rec_pos;
}
}

//function for checking recording status
bool CalliopeMicrophone::isRecording()
{
return active;
}

#endif
Loading