arduino-audio-tools
Loading...
Searching...
No Matches
PWMDriverTangNano.h
Go to the documentation of this file.
1#pragma once
2#if defined(ARDUINO_ARCH_TANGNANO20K)
5#if TANGNANO20K_PWM_AUDIO
6#include <PWMAudio.h>
7#endif
8
9namespace audio_tools {
10
21class PWMDriverTangNanoTimer : public PWMDriverBase {
22 public:
23 PWMDriverTangNanoTimer() { LOGD("PWMDriverTangNanoTimer"); }
24
25 // Ends the output
26 virtual void end() override {
27 TRACED();
28 ticker.end();
29 is_timer_started = false;
30 for (int j = 0; j < pins.size(); j++) {
31 pinMode(pins[j], OUTPUT); // releases the PWM channel
32 }
33 pins.clear();
34 deleteBuffer();
35 }
36
37 protected:
38 Vector<int> pins;
39 AudioTimer ticker; // calls a callback repeatedly with a timeout
40
43 virtual void startTimer() override {
44 TRACED();
45 if (!is_timer_started) {
46 ticker.setCallbackParameter(this);
47 int sample_rate = effectiveOutputSampleRate();
48 if (isDecimateActive()) {
49 LOGI("Using reduced sample rate: %d", sample_rate);
50 }
51 is_timer_started =
52 ticker.begin(defaultPWMAudioOutputCallback, sample_rate, HZ);
53 }
54 }
55
57 virtual void setupPWM() {
58 TRACED();
59 if (audio_config.pwm_frequency == 0) {
60 audio_config.pwm_frequency = PWM_AUDIO_FREQUENCY;
61 }
62 analogWriteResolution(audio_config.resolution);
63
64 pins.resize(audio_config.channels);
65 for (int j = 0; j < audio_config.channels; j++) {
66 int gpio = audio_config.pins()[j];
67 LOGI("PWM Pin: %d", gpio);
68 pins[j] = gpio;
69 analogWriteFrequency(gpio, audio_config.pwm_frequency);
70 analogWrite(gpio, maxOutputValue() / 2);
71 }
72 }
73
75 virtual void setupTimer() {}
76
77 virtual int maxChannels() { return PIN_PWM_COUNT; };
78
80 virtual int maxOutputValue() { return (1 << audio_config.resolution) - 1; }
81
84 virtual void pwmWrite(int channel, int value) {
85 analogWrite(pins[channel], value);
86 }
87
89 static void defaultPWMAudioOutputCallback(void *obj) {
90 PWMDriverTangNanoTimer *self = (PWMDriverTangNanoTimer *)obj;
91 if (self != nullptr) {
92 self->playNextFrame();
93 }
94 }
95};
96
97#if TANGNANO20K_PWM_AUDIO
98
108class PWMDriverTangNano : public PWMDriverBase {
109 public:
110 PWMDriverTangNano() { LOGD("PWMDriverTangNano"); }
111
113 virtual PWMConfig defaultConfig() {
114 PWMConfig cfg;
115 cfg.sample_rate = 44100;
116 cfg.channels = 2;
117 return cfg;
118 }
119
120 virtual void end() override {
121 TRACED();
122 ::PWMAudio.end();
123 is_timer_started = false;
124 deleteBuffer();
125 }
126
128 virtual size_t write(const uint8_t *data, size_t len) override {
129 if (!is_timer_started) return 0;
130 if (audio_config.bits_per_sample == 16) {
131 return ::PWMAudio.write(data, len);
132 }
133 // convert to 16 bits
134 int bytes = bytesPerSample();
135 size_t samples = len / bytes;
136 int16_t tmp[64];
137 size_t pos = 0;
138 while (pos < samples) {
139 size_t n = min(samples - pos, (size_t)64);
140 for (size_t j = 0; j < n; j++) {
141 tmp[j] = toInt16(data + (pos + j) * bytes);
142 }
143 ::PWMAudio.write((const uint8_t *)tmp, n * sizeof(int16_t));
144 pos += n;
145 }
146 return samples * bytes;
147 }
148
150 virtual int availableForWrite() override {
151 return ::PWMAudio.availableForWrite() / 2 * bytesPerSample();
152 }
153
154 int effectiveOutputSampleRate() override { return audio_config.sample_rate; }
155
156 protected:
157 virtual void setupPWM() {
158 TRACED();
159 if (audio_config.pwm_frequency == 0) {
160 audio_config.pwm_frequency = PWM_AUDIO_FREQUENCY;
161 }
162 PWMAudioConfig cfg = ::PWMAudio.defaultConfig();
163 cfg.sampleRate = audio_config.sample_rate;
164 cfg.channels = audio_config.channels;
165 cfg.pwmRate = audio_config.pwm_frequency;
166 // buffer size is in bytes: the ring buffer is in frames
167 int frames = audio_config.buffer_size * audio_config.buffers /
168 (audio_config.channels * bytesPerSample());
169 if (frames > 0xFFFF) frames = 0xFFFF;
170 if (frames > 0) cfg.ringSamples = frames;
171 is_timer_started = ::PWMAudio.begin(cfg);
172 if (!is_timer_started) {
173 LOGE("PWMAudio.begin failed");
174 }
175 }
176
178 virtual void setupTimer() {}
179 virtual void startTimer() {}
180 virtual int maxChannels() { return 2; };
181 virtual int maxOutputValue() { return 0xFFFF; }
182 virtual void pwmWrite(int channel, int value) {}
183 bool isDecimateActive() override { return false; }
184 int decimation() override { return 1; }
185
187 int bytesPerSample() {
188 return audio_config.bits_per_sample == 24 ? sizeof(int24_t)
189 : audio_config.bits_per_sample / 8;
190 }
191
192 int16_t toInt16(const uint8_t *data) {
193 switch (audio_config.bits_per_sample) {
194 case 8:
195 return (int16_t)(*(int8_t *)data) << 8;
196 case 24:
197 return (int32_t)(*(int24_t *)data) >> 8;
198 case 32:
199 return (*(int32_t *)data) >> 16;
200 default:
201 return *(int16_t *)data;
202 }
203 }
204};
205
207using PWMDriver = PWMDriverTangNano;
208
209#else
210
212using PWMDriver = PWMDriverTangNanoTimer;
213
214#endif
215
216} // namespace audio_tools
217
218#endif
#define OUTPUT
Definition Arduino.h:38
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
PWMDriverAVR PWMDriver
Platform-specific PWM driver alias for AVR.
Definition PWMDriverAVR.h:13
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
int24_4bytes_t int24_t
Definition int24_t.h:12
void defaultPWMAudioOutputCallback()
Definition PWMDriverAVR.h:134
void pinMode(digital_pin_t pin, int mode)
Definition Arduino.h:286
PWMConfigAVR PWMConfig
Definition PWMConfigAVR.h:53
constexpr const _Ep * end(initializer_list< _Ep > __il) noexcept
Definition InitializerList.h:63
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:58
#define PWM_AUDIO_FREQUENCY
Definition tangnano20k.h:23
#define PIN_PWM_COUNT
Definition tangnano20k.h:21