33
44#if defined(ADAFRUIT_MONSTER_M4SK_EXPRESS)
55
6+ #include " globals.h"
67#include < SPI.h>
78
89#define MIN_PITCH_HZ 65
910#define MAX_PITCH_HZ 1600
1011#define TYP_PITCH_HZ 175
1112
12- // Playback timer stuff - use TC3 on MONSTER M4SK (no TC4 on this board)
13- #define TIMER TC3
14- #define TIMER_IRQN TC3_IRQn
15- #define TIMER_IRQ_HANDLER TC3_Handler
16- #define TIMER_GCLK_ID TC3_GCLK_ID
17- #define TIMER_GCM_ID GCM_TC2_TC3
18-
1913// PDM mic allows 1.0 to 3.25 MHz max clock (2.4 typical).
2014// SPI native max is is 24 MHz, so available speeds are 12, 6, 3 MHz.
2115#define SPI_BITRATE 3000000
@@ -103,6 +97,7 @@ static int16_t playbackIndexJumped;
10397static uint16_t nextOut = 2048 ;
10498
10599float voicePitch (float p);
100+ static void playCallback (void );
106101
107102// START PITCH SHIFT (no arguments) ----------------------------------------
108103
@@ -150,37 +145,7 @@ bool voiceSetup(bool modEnable) {
150145
151146 analogWriteResolution (12 );
152147
153- // Feed TIMER off GCLK1 (already set to 48 MHz by Arduino core)
154- GCLK->PCHCTRL [TIMER_GCLK_ID].bit .CHEN = 0 ; // Disable channel
155- while (GCLK->PCHCTRL [TIMER_GCLK_ID].bit .CHEN ); // Wait for disable
156- GCLK_PCHCTRL_Type pchctrl;
157- pchctrl.bit .GEN = GCLK_PCHCTRL_GEN_GCLK1_Val;
158- pchctrl.bit .CHEN = 1 ;
159- GCLK->PCHCTRL [TIMER_GCLK_ID].reg = pchctrl.reg ;
160- while (!GCLK->PCHCTRL [TIMER_GCLK_ID].bit .CHEN ); // Wait for enable
161-
162- // Disable timer before configuring it
163- TIMER->COUNT16 .CTRLA .bit .ENABLE = 0 ;
164- while (TIMER->COUNT16 .SYNCBUSY .bit .ENABLE );
165-
166- // 16-bit counter mode, 1:1 prescale, match-frequency generation mode
167- TIMER->COUNT16 .CTRLA .bit .MODE = TC_CTRLA_MODE_COUNT16;
168- TIMER->COUNT16 .CTRLA .bit .PRESCALER = TC_CTRLA_PRESCALER_DIV1_Val;
169- TIMER->COUNT16 .WAVE .bit .WAVEGEN = TC_WAVE_WAVEGEN_MFRQ_Val;
170-
171- TIMER->COUNT16 .CTRLBCLR .reg = TC_CTRLBCLR_DIR; // Count up
172- while (TIMER->COUNT16 .SYNCBUSY .bit .CTRLB );
173-
174- voicePitch (1.0 ); // Set timer interval
175-
176- TIMER->COUNT16 .INTENSET .reg = TC_INTENSET_OVF; // Overflow interrupt
177- NVIC_DisableIRQ (TIMER_IRQN);
178- NVIC_ClearPendingIRQ (TIMER_IRQN);
179- NVIC_SetPriority (TIMER_IRQN, 0 ); // Top priority
180- NVIC_EnableIRQ (TIMER_IRQN);
181-
182- TIMER->COUNT16 .CTRLA .bit .ENABLE = 1 ; // Enable timer
183- while (TIMER->COUNT16 .SYNCBUSY .bit .ENABLE ); // Wait for it
148+ voicePitch (1.0 ); // Set timer interval & callback
184149
185150 return true ; // Success
186151}
@@ -196,14 +161,15 @@ bool voiceSetup(bool modEnable) {
196161// adjustment (after appying constraints) will be returned.
197162float voicePitch (float p) {
198163 float desiredPlaybackRate = sampleRate * p;
199- int32_t period = (int32_t )(48000000.0 / desiredPlaybackRate + 0.5 );
200- if (period > 2500 ) period = 2500 ; // Hard limit is 65536, 2.5K is a practical limit
201- else if (period < 250 ) period = 250 ; // Leave some cycles for IRQ handler
202- TIMER->COUNT16 .CC [0 ].reg = period - 1 ;
203- while (TIMER->COUNT16 .SYNCBUSY .bit .CC0 );
204- float actualPlaybackRate = 48000000.0 / (float )period;
164+ int32_t period = (int32_t )(48000000.0 / 16.0 / desiredPlaybackRate + 0.5 );
165+ if (period > 160 ) period = 160 ; // Hard limit is 65536, 160 is a practical limit
166+ else if (period < 16 ) period = 16 ; // Leave some cycles for IRQ handler
167+ float actualPlaybackRate = 48000000.0 / 16.0 / (float )period;
205168 p = (actualPlaybackRate / sampleRate); // New pitch
206169 jumpThreshold = (int )(jump * p + 0.5 );
170+
171+ arcada.timerCallback ((int )actualPlaybackRate, playCallback);
172+
207173 return p;
208174}
209175
@@ -223,9 +189,11 @@ void voiceGain(float g) {
223189void voiceMod (uint32_t freq, uint8_t waveform) {
224190 if (modBuf) { // Ignore if no modulation buffer allocated
225191 if (freq < MOD_MIN) freq = MOD_MIN;
192+ /*
226193 uint16_t period = TIMER->COUNT16.CC[0].reg + 1; // Audio out timer ticks
227- float playbackRate = 48000000.0 / (float )period; // Audio out samples/sec
194+ float playbackRate = 48000000.0 / 16.0 / (float)period; // Audio out samples/sec
228195 modLen = (int)(playbackRate / freq + 0.5);
196+ */
229197 if (modLen < 2 ) modLen = 2 ;
230198 if (waveform > 4 ) waveform = 4 ;
231199 modWave = waveform;
@@ -397,10 +365,8 @@ void PDM_SERCOM_HANDLER(void) {
397365 evenWord ^= 1 ;
398366}
399367
400- // Playback timer interrupt
401- void TIMER_IRQ_HANDLER (void ) {
402- TIMER->COUNT16 .INTFLAG .reg = TC_INTFLAG_OVF;
403-
368+ // Playback timer callback
369+ static void playCallback (void ) {
404370 // Modulation is done on the output (rather than the input) because
405371 // pitch-shifting modulated input would cause weird waveform
406372 // discontinuities. This does require recalculating the modulation table
0 commit comments