Skip to content

Commit 5301078

Browse files
Merge pull request #854 from adafruit/philb-branch
Add mic gain and some initial work on modulation
2 parents b36c2b6 + fa4d41c commit 5301078

4 files changed

Lines changed: 66 additions & 3 deletions

File tree

M4_Eyes/M4_Eyes.ino

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,11 @@ void setup() {
420420

421421
#if defined(ADAFRUIT_MONSTER_M4SK_EXPRESS)
422422
if(voiceOn) {
423-
if(!voiceSetup()) {
423+
if(!voiceSetup(false)) {
424424
Serial.println("Voice init fail, continuing without");
425425
voiceOn = false;
426426
} else {
427+
voiceGain(gain);
427428
currentPitch = voicePitch(currentPitch);
428429
digitalWrite(20, HIGH); // Speaker on
429430
}

M4_Eyes/file.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ void loadConfig(char *filename) {
376376
v = doc["voice"];
377377
if(v.is<bool>()) voiceOn = v.as<bool>();
378378
currentPitch = defaultPitch = doc["pitch"] | defaultPitch;
379+
gain = doc["gain"] | gain;
379380
#endif // ADAFRUIT_MONSTER_M4SK_EXPRESS
380381
}
381382
file.close();

M4_Eyes/globals.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ GLOBAL_VAR uint32_t boopThreshold GLOBAL_INIT(17500);
8888
GLOBAL_VAR bool voiceOn GLOBAL_INIT(false);
8989
GLOBAL_VAR float currentPitch GLOBAL_INIT(1.0);
9090
GLOBAL_VAR float defaultPitch GLOBAL_INIT(1.0);
91+
GLOBAL_VAR float gain GLOBAL_INIT(1.0);
9192
#endif
9293

9394
// EYE-RELATED STRUCTURES --------------------------------------------------
@@ -214,9 +215,10 @@ extern uint8_t *writeDataToFlash(uint8_t *src, uint32_t len);
214215

215216
// Functions in pdmvoice.cpp
216217
#if defined(ADAFRUIT_MONSTER_M4SK_EXPRESS)
217-
extern bool voiceSetup(void);
218+
extern bool voiceSetup(bool modEnable);
218219
extern float voicePitch(float p);
219220
extern void voiceGain(float g);
221+
extern void voiceMod(uint32_t freq, uint8_t waveform);
220222
extern volatile uint16_t voiceLastReading;
221223
#endif // ADAFRUIT_MONSTER_M4SK_EXPRESS
222224

M4_Eyes/pdmvoice.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ static uint16_t dcOffsetNext = 32768; // between these two values
7676

7777
static uint16_t micGain = 256; // 1:1
7878

79+
#define MOD_MIN 40 // Lowest supported modulation pitch (lower = more RAM use)
80+
static uint8_t modWave = 0; // Modulation wave type (none, sine, square, tri, saw)
81+
static uint8_t *modBuf = NULL; // Modulation waveform buffer
82+
static uint32_t modIndex = 0; // Current position in modBuf
83+
static uint32_t modLen = 0; // Currently used amount of modBuf based on modFreq
84+
7985
// Just playing back directly from the recording circular buffer produces
8086
// audible clicks as the waveforms rarely align at the beginning and end of
8187
// the buffer. So what we do is advance or push back the playback index a
@@ -100,13 +106,20 @@ float voicePitch(float p);
100106

101107
// START PITCH SHIFT (no arguments) ----------------------------------------
102108

103-
bool voiceSetup(void) {
109+
bool voiceSetup(bool modEnable) {
104110

105111
// Allocate circular buffer for audio
106112
if(NULL == (recBuf = (uint16_t *)malloc(recBufSize * sizeof(uint16_t)))) {
107113
return false; // Fail
108114
}
109115

116+
// Allocate buffer for voice modulation, if enabled
117+
if(modEnable) {
118+
// 250 comes from min period in voicePitch()
119+
modBuf = (uint8_t *)malloc((int)(48000000.0 / 250.0 / MOD_MIN + 0.5));
120+
// If malloc fails, program will continue without modulation
121+
}
122+
110123
// Set up PDM microphone input -------------------------------------------
111124

112125
PDM_SPI.begin();
@@ -202,6 +215,47 @@ void voiceGain(float g) {
202215
else micGain = (uint16_t)(g * 256.0 + 0.5);
203216
}
204217

218+
// SET MODULATION ----------------------------------------------------------
219+
220+
// This is a work in progress and NOT FUNCTIONAL YET
221+
222+
void voiceMod(uint32_t freq, uint8_t waveform) {
223+
if(modBuf) { // Ignore if no modulation buffer allocated
224+
if(freq < MOD_MIN) freq = MOD_MIN;
225+
uint16_t period = TIMER->COUNT16.CC[0].reg + 1;
226+
float playbackRate = 48000000.0 / (float)period; // samples/sec
227+
modLen = (int)(playbackRate / freq + 0.5);
228+
if(modLen < 2) modLen = 2;
229+
if(waveform > 4) waveform = 4;
230+
modWave = waveform;
231+
switch(modWave) {
232+
case 0: // None
233+
memset(modBuf, 255, modLen);
234+
break;
235+
case 1: // Square
236+
memset(modBuf, 255, modLen / 2);
237+
memset(&modBuf[modLen / 2], 0, modLen - modLen / 2);
238+
break;
239+
case 2: // Sine
240+
for(int i=0; i<modLen; i++) {
241+
modBuf[i] = (int)((sin(M_PI * 2.0 * (float)i / (float)modLen) + 1.0) * 0.5 * 255.0 + 0.5);
242+
}
243+
break;
244+
case 3: // Triangle
245+
for(int i=0; i<modLen; i++) {
246+
modBuf[i] = (int)(fabs(0.5 - (float)i / (float)modLen) * 2.0 * 255.0 + 0.5);
247+
}
248+
break;
249+
case 4: // Sawtooth (increasing)
250+
for(int i=0; i<modLen; i++) {
251+
modBuf[i] = (int)((float)i / (float)(modLen - 1) * 255.0 + 0.5);
252+
}
253+
break;
254+
}
255+
}
256+
}
257+
258+
205259
// INTERRUPT HANDLERS ------------------------------------------------------
206260

207261
static uint16_t const sincfilter[64] = { 0, 2, 9, 21, 39, 63, 94, 132, 179, 236, 302, 379, 467, 565, 674, 792, 920, 1055, 1196, 1341, 1487, 1633, 1776, 1913, 2042, 2159, 2263, 2352, 2422, 2474, 2506, 2516, 2506, 2474, 2422, 2352, 2263, 2159, 2042, 1913, 1776, 1633, 1487, 1341, 1196, 1055, 920, 792, 674, 565, 467, 379, 302, 236, 179, 132, 94, 63, 39, 21, 9, 2, 0, 0 };
@@ -347,6 +401,11 @@ void PDM_SERCOM_HANDLER(void) {
347401
void TIMER_IRQ_HANDLER(void) {
348402
TIMER->COUNT16.INTFLAG.reg = TC_INTFLAG_OVF;
349403

404+
if(modWave) {
405+
nextOut = (((int32_t)nextOut - 2048) * (modBuf[modIndex] + 1) / 256) + 2048;
406+
if(++modIndex >= modLen) modIndex = 0;
407+
}
408+
350409
// Do analog writes pronto so output timing is consistent
351410
analogWrite(A0, nextOut);
352411
analogWrite(A1, nextOut);

0 commit comments

Comments
 (0)