Mozzi  version v2.0
sound synthesis library for Arduino
MozziGuts_impl_MBED.hpp
1 /*
2  * MozziGuts_impl_MBED.hpp
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2023-2024 T. Combriat and the Mozzi Team
7  *
8  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9  *
10 */
11 
12 #if !(IS_MBED())
13 # error "Wrong implementation included for this platform"
14 #endif
15 
16 #define CHUNKSIZE 64
17 
18 namespace MozziPrivate {
19 
20 ////// BEGIN analog input code ////////
21 
22 #if MOZZI_IS(MOZZI_AUDIO_INPUT, MOZZI_AUDIO_INPUT_STANDARD)
23 #define MOZZI__LEGACY_AUDIO_INPUT_IMPL 0
24 
25 } // namespace MozziPrivate
26 #include <Arduino_AdvancedAnalog.h>
27 namespace MozziPrivate {
28 
31 int inbufpos=0;
32 
33 bool audioInputAvailable() {
34  if (inbufpos >= CHUNKSIZE) {
35  if (!adc.available()) return false;
37  memcpy(inbuf,buf.data(), CHUNKSIZE*sizeof(Sample));
38  inbufpos = 0;
39  buf.release();
40  return true;
41  }
42  else return true;
43 }
45  return inbuf[inbufpos++];
46 }
47 
48 
49 static void startAudioInput() {
51  Serial.println("Failed to start analog acquisition!");
52  while (1);
53  }
54 }
55 #else
56 static void startAudioInput() {}; // dummy to ease coding
57 #endif
58 
59 #if MOZZI_IS(MOZZI_ANALOG_READ, MOZZI_ANALOG_READ_STANDARD)
60 #error not yet implemented
61 /** NOTE: This section deals with implementing (fast) asynchronous analog reads, which form the backbone of mozziAnalogRead(), but also of USE_AUDIO_INPUT (if enabled).
62  * 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
63  * #define, above */
64 
65 // Insert here code to read the result of the latest asynchronous conversion, when it is finished.
66 // You can also provide this as a function returning unsigned int, should it be more complex on your platform
67 #define getADCReading() 0
68 
69 /** NOTE: On "pins" vs. "channels" vs. "indices"
70  * "Pin" is the pin number as would usually be specified by the user in mozziAnalogRead().
71  * "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.
72  * In other words, this is an internal representation of "pin".
73  * "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
74  * same as "channel" (e.g. on AVR), however, on platforms where ADC-capable "channels" are not numbered sequentially starting from 0, the channel needs
75  * to be converted to a suitable index.
76  *
77  * In summary, the semantics are roughly
78  * mozziAnalogRead(pin) -> _ADCimplementation_(channel) -> analog_readings[index]
79  * Implement adcPinToChannelNum() and channelNumToIndex() to perform the appropriate mapping.
80  */
81 // NOTE: Theoretically, adcPinToChannelNum is public API for historical reasons, thus cannot be replaced by a define
83  return pin;
84 }
85 
86 /** NOTE: Code needed to trigger a conversion on a new channel */
88 }
89 
90 /** 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
91  * adcStartConversion(), and simply call adcStartConversion(previous_channel), here. */
93 }
94 
95 /** 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.
96  * This particular function is not super important, so may be ok to leave empty, at least, if the ADC is fast enough by default. */
98 }
99 
100 /** NOTE: Code needed to initialize the ADC for asynchronous reads. Typically involves setting up an interrupt handler for when conversion is done, and
101  * possibly calibration. */
102 void setupMozziADC(int8_t speed) {
103 }
104 
105 #endif
106 
107 ////// END analog input code ////////
108 
109 ////// BEGIN audio output code //////
110 #if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_EXTERNAL_TIMED)
111 
112 #define US_PER_AUDIO_TICK (1000000L / MOZZI_AUDIO_RATE)
113 } // namespace MozziPrivate
114 #include <mbed.h>
115 namespace MozziPrivate {
117 
118 volatile bool audio_output_requested = false;
119 inline void defaultAudioOutputCallback() {
120  audio_output_requested = true;
121 }
122 
123 #define AUDIO_HOOK_HOOK { if (audio_output_requested) { audio_output_requested = false; defaultAudioOutput(); } }
124 
125 static void startAudio() {
127  startAudioInput();
128 }
129 
130 void stopMozzi() {
132 }
133 
134 #elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_INTERNAL_DAC)
135 
136 } // namespace MozziPrivate
137 #include <Arduino_AdvancedAnalog.h>
138 namespace MozziPrivate {
139 
142 #if (MOZZI_AUDIO_CHANNELS > 1)
145 #endif
146 int bufpos = 0;
147 
148 inline void commitBuffer(Sample buffer[], AdvancedDAC &dac) {
150  // NOTE: Yes, this is silly code, and originated as an accident. Somehow it appears to help _a little_ against current problem wrt DAC stability
151  for (unsigned int i=0;i<CHUNKSIZE;i++) memcpy(dmabuf.data(), buffer, CHUNKSIZE*sizeof(Sample));
152  dac.write(dmabuf);
153 }
154 
155 inline void audioOutput(const AudioOutput f) {
156  if (bufpos >= CHUNKSIZE) {
158 #if (MOZZI_AUDIO_CHANNELS > 1)
160 #endif
161  bufpos = 0;
162  }
164 #if (MOZZI_AUDIO_CHANNELS > 1)
166 #endif
167  ++bufpos;
168 }
169 
170 bool canBufferAudioOutput() {
171  return (bufpos < CHUNKSIZE || (dac1.available()
172 #if (MOZZI_AUDIO_CHANNELS > 1)
173  && dac2.available()
174 #endif
175  ));
176 }
177 
178 static void startAudio() {
179  //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!
181  Serial.println("Failed to start DAC1 !");
182  while (1);
183  }
184 #if (MOZZI_AUDIO_CHANNELS > 1)
186  Serial.println("Failed to start DAC2 !");
187  while (1);
188  }
189 #endif
190  startAudioInput();
191 }
192 
193 void stopMozzi() {
194  dac1.stop();
195 #if (MOZZI_AUDIO_CHANNELS > 1)
196  dac2.stop();
197 #endif
198 }
199 
200 #elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PDM_VIA_SERIAL)
201 
202 } // namespace MozziPrivate
203 #include <mbed.h>
204 namespace MozziPrivate {
205 
208 
209 bool canBufferAudioOutput() {
210  return serial_out1.writable();
211 }
212 
213 inline void audioOutput(const AudioOutput f) {
214  for (uint8_t i = 0; i < MOZZI_PDM_RESOLUTION*4; ++i) {
216  }
218 }
219 
220 static void startAudio() {
221  serial_out1.set_baud(MOZZI_AUDIO_RATE*MOZZI_PDM_RESOLUTION*40); // NOTE: 40 == 4 * (8 bits + stop-bits)
223 }
224 
225 void stopMozzi() {
226 #warning implement me
227 }
228 
229 
230 #endif
231 ////// END audio output code //////
232 
233 //// BEGIN Random seeding ////////
234 void MozziRandPrivate::autoSeed() {
235 #warning Automatic random seeding is not implemented on this platform
236 }
237 //// END Random seeding ////////
238 
239 } // namespace MozziPrivate
240 
241 #undef CHUNKSIZE
242 #undef US_PER_AUDIO_TICK