forked from sensorium/Mozzi
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMozziGuts_impl_MBED.hpp
More file actions
234 lines (190 loc) · 7.45 KB
/
MozziGuts_impl_MBED.hpp
File metadata and controls
234 lines (190 loc) · 7.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/*
* MozziGuts.cpp
*
* Copyright 2012 Tim Barrass.
*
* This file is part of Mozzi.
*
* Mozzi by Tim Barrass is licensed under a Creative Commons
* Attribution-NonCommercial-ShareAlike 4.0 International License.
*
*/
#if !(IS_MBED())
# error "Wrong implementation included for this platform"
#endif
#define CHUNKSIZE 64
////// BEGIN analog input code ////////
#if (USE_AUDIO_INPUT)
#define AUDIO_INPUT_MODE AUDIO_INPUT_CUSTOM
#include <Arduino_AdvancedAnalog.h>
AdvancedADC adc(AUDIO_INPUT_PIN);
Sample inbuf[CHUNKSIZE];
int inbufpos=0;
bool audioInputAvailable() {
if (inbufpos >= CHUNKSIZE) {
if (!adc.available()) return false;
SampleBuffer buf = adc.read();
memcpy(inbuf,buf.data(), CHUNKSIZE*sizeof(Sample));
inbufpos = 0;
buf.release();
return true;
}
else return true;
}
AudioOutputStorage_t readAudioInput(){
return inbuf[inbufpos++];
}
static void startAudioInput() {
if (!adc.begin(AN_RESOLUTION_12, AUDIO_RATE, CHUNKSIZE, 256/CHUNKSIZE)) {
Serial.println("Failed to start analog acquisition!");
while (1);
}
}
#endif
/** NOTE: This section deals with implementing (fast) asynchronous analog reads, which form the backbone of mozziAnalogRead(), but also of USE_AUDIO_INPUT (if enabled).
* This template provides empty/dummy implementations to allow you to skip over this section, initially. Once you have an implementation, be sure to enable the
* #define, below: */
//#define MOZZI_FAST_ANALOG_IMPLEMENTED
// Insert here code to read the result of the latest asynchronous conversion, when it is finished.
// You can also provide this as a function returning unsigned int, should it be more complex on your platform
#define getADCReading() 0
/** NOTE: On "pins" vs. "channels" vs. "indices"
* "Pin" is the pin number as would usually be specified by the user in mozziAnalogRead().
* "Channel" is an internal ADC channel number corresponding to that pin. On many platforms this is simply the same as the pin number, on others it differs.
* In other words, this is an internal representation of "pin".
* "Index" is the index of the reading for a certain pin/channel in the array of analog_readings, ranging from 0 to NUM_ANALOG_PINS. This, again may be the
* same as "channel" (e.g. on AVR), however, on platforms where ADC-capable "channels" are not numbered sequentially starting from 0, the channel needs
* to be converted to a suitable index.
*
* In summary, the semantics are roughly
* mozziAnalogRead(pin) -> _ADCimplementation_(channel) -> analog_readings[index]
* Implement adcPinToChannelNum() and channelNumToIndex() to perform the appropriate mapping.
*/
// NOTE: Theoretically, adcPinToChannelNum is public API for historical reasons, thus cannot be replaced by a define
#define channelNumToIndex(channel) channel
uint8_t adcPinToChannelNum(uint8_t pin) {
return pin;
}
/** NOTE: Code needed to trigger a conversion on a new channel */
void adcStartConversion(uint8_t channel) {
#warning Fast analog read not implemented on this platform
}
/** NOTE: Code needed to trigger a subsequent conversion on the latest channel. If your platform has no special code for it, you should store the channel from
* adcStartConversion(), and simply call adcStartConversion(previous_channel), here. */
void startSecondADCReadOnCurrentChannel() {
#warning Fast analog read not implemented on this platform
}
/** NOTE: Code needed to set up faster than usual analog reads, e.g. specifying the number of CPU cycles that the ADC waits for the result to stabilize.
* This particular function is not super important, so may be ok to leave empty, at least, if the ADC is fast enough by default. */
void setupFastAnalogRead(int8_t speed) {
#warning Fast analog read not implemented on this platform
}
/** NOTE: Code needed to initialize the ADC for asynchronous reads. Typically involves setting up an interrupt handler for when conversion is done, and
* possibly calibration. */
void setupMozziADC(int8_t speed) {
#warning Fast analog read not implemented on this platform
#if (USE_AUDIO_INPUT)
startAudioInput();
#endif
}
/* NOTE: Most platforms call a specific function/ISR when conversion is complete. Provide this function, here.
* From inside its body, simply call advanceADCStep(). E.g.:
void stm32_adc_eoc_handler() {
advanceADCStep();
}
*/
////// END analog input code ////////
////// BEGIN audio output code //////
#if (EXTERNAL_AUDIO_OUTPUT == true)
#define US_PER_AUDIO_TICK (1000000L / AUDIO_RATE)
#include <mbed.h>
mbed::Ticker audio_output_timer;
volatile bool audio_output_requested = false;
inline void defaultAudioOutputCallback() {
audio_output_requested = true;
}
#define AUDIO_HOOK_HOOK { if (audio_output_requested) { audio_output_requested = false; defaultAudioOutput(); } }
static void startAudio() {
audio_output_timer.attach_us(&defaultAudioOutputCallback, US_PER_AUDIO_TICK);
}
void stopMozzi() {
audio_output_timer.detach();
}
#elif (MBED_AUDIO_OUT_MODE == INTERNAL_DAC)
#include <Arduino_AdvancedAnalog.h>
AdvancedDAC dac1(AUDIO_CHANNEL_1_PIN);
Sample buf1[CHUNKSIZE];
#if (AUDIO_CHANNELS > 1)
AdvancedDAC dac2(AUDIO_CHANNEL_2_PIN);
Sample buf2[CHUNKSIZE];
#endif
int bufpos = 0;
inline void commitBuffer(Sample buffer[], AdvancedDAC &dac) {
SampleBuffer dmabuf = dac.dequeue();
// NOTE: Yes, this is silly code, and originated as an accident. Somehow it appears to help _a little_ against current problem wrt DAC stability
for (unsigned int i=0;i<CHUNKSIZE;i++) memcpy(dmabuf.data(), buffer, CHUNKSIZE*sizeof(Sample));
dac.write(dmabuf);
}
/** NOTE: This is the function that actually write a sample to the output. In case of EXTERNAL_AUDIO_OUTPUT == true, it is provided by the library user, instead. */
inline void audioOutput(const AudioOutput f) {
if (bufpos >= CHUNKSIZE) {
commitBuffer(buf1, dac1);
#if (AUDIO_CHANNELS > 1)
commitBuffer(buf2, dac2);
#endif
bufpos = 0;
}
buf1[bufpos] = f.l()+AUDIO_BIAS;
#if (AUDIO_CHANNELS > 1)
buf2[bufpos] = f.r()+AUDIO_BIAS;
#endif
++bufpos;
}
bool canBufferAudioOutput() {
return (bufpos < CHUNKSIZE || (dac1.available()
#if (AUDIO_CHANNELS > 1)
&& dac2.available()
#endif
));
}
static void startAudio() {
//NOTE: DAC setup currently affected by https://github.com/arduino-libraries/Arduino_AdvancedAnalog/issues/35 . Don't expect this to work, until using a fixed version fo Arduino_AdvancedAnalog!
if (!dac1.begin(AN_RESOLUTION_12, AUDIO_RATE, CHUNKSIZE, 256/CHUNKSIZE)) {
Serial.println("Failed to start DAC1 !");
while (1);
}
#if (AUDIO_CHANNELS > 1)
if (!dac2.begin(AN_RESOLUTION_12, AUDIO_RATE, CHUNKSIZE, 256/CHUNKSIZE)) {
Serial.println("Failed to start DAC2 !");
while (1);
}
#endif
}
void stopMozzi() {
dac1.stop();
#if (AUDIO_CHANNELS > 1)
dac2.stop();
#endif
}
#elif (MBED_AUDIO_OUT_MODE == PDM_VIA_SERIAL)
#include <mbed.h>
mbed::BufferedSerial serial_out1(digitalPinToPinName(PDM_SERIAL_UART_TX_CHANNEL_1), digitalPinToPinName(PDM_SERIAL_UART_RX_CHANNEL_1));
uint8_t buf[PDM_RESOLUTION*4];
bool canBufferAudioOutput() {
return serial_out1.writable();
}
inline void audioOutput(const AudioOutput f) {
for (uint8_t i = 0; i < PDM_RESOLUTION*4; ++i) {
buf[i] = pdmCode8(f.l()+AUDIO_BIAS);
}
serial_out1.write(&buf, PDM_RESOLUTION*4);
}
static void startAudio() {
serial_out1.set_baud(AUDIO_RATE*PDM_RESOLUTION*40); // NOTE: 40 = 4 * (8 bits + stop-bits)
serial_out1.set_format(8, mbed::BufferedSerial::None, 1);
}
void stopMozzi() {
#warning implement me
}
#endif
////// END audio output code //////