Mozzi  version v1.1.0
sound synthesis library for Arduino
MozziGuts_impl_ESP8266.hpp
1 /*
2  * MozziGuts.cpp
3  *
4  * Copyright 2012 Tim Barrass.
5  *
6  * This file is part of Mozzi.
7  *
8  * Mozzi by Tim Barrass is licensed under a Creative Commons
9  * Attribution-NonCommercial-ShareAlike 4.0 International License.
10  *
11  */
12 
13 #if !(IS_ESP8266())
14 # error "Wrong implementation included for this platform"
15 #endif
16 
17 ////// BEGIN analog input code ////////
18 //#define MOZZI_FAST_ANALOG_IMPLEMENTED // not yet
19 #define getADCReading() 0
20 #define channelNumToIndex(channel) channel
21 uint8_t adcPinToChannelNum(uint8_t pin) {
22  return pin;
23 }
24 void adcStartConversion(uint8_t channel) {
25 #warning Fast analog read not implemented on this platform
26 }
27 void startSecondADCReadOnCurrentChannel() {
28 #warning Fast analog read not implemented on this platform
29 }
30 void setupFastAnalogRead(int8_t speed) {
31 #warning Fast analog read not implemented on this platform
32 }
33 void setupMozziADC(int8_t speed) {
34 #warning Fast analog read not implemented on this platform
35 }
36 ////// END analog input code ////////
37 
38 
39 
40 //// BEGIN AUDIO OUTPUT code ///////
41 #define LOOP_YIELD yield();
42 
43 #include <uart.h>
44 #include <i2s.h>
45 uint16_t output_buffer_size = 0;
46 
47 #if (EXTERNAL_AUDIO_OUTPUT != true) // otherwise, the last stage - audioOutput() - will be provided by the user
48 # include "AudioConfigESP.h"
49 
51 # include <i2s.h>
52 inline bool canBufferAudioOutput() {
53  return (i2s_available() >= PDM_RESOLUTION);
54 }
55 inline void audioOutput(const AudioOutput f) {
56  for (uint8_t words = 0; words < PDM_RESOLUTION; ++words) {
57  i2s_write_sample(pdmCode32(f.l()+AUDIO_BIAS));
58  }
59 }
61 # include <i2s.h>
62 inline bool canBufferAudioOutput() {
63  return (i2s_available() >= PDM_RESOLUTION);
64 }
65 inline void audioOutput(const AudioOutput f) {
66  i2s_write_lr(f.l(), f.r()); // Note: i2s_write expects zero-centered output
67 }
68 # else // (ESP_AUDIO_OUT_MODE == PDM_VIA_SERIAL)
69 // NOTE: This intermediate step is needed because the output timer is running at a rate higher than AUDIO_RATE, and we need to rely on the (tiny)
70 // serial buffer itself to achieve appropriate rate control
71 void CACHED_FUNCTION_ATTR esp8266_serial_audio_output() {
72  // Note: That unreadble mess is an optimized version of Serial1.availableForWrite()
73  while ((UART_TX_FIFO_SIZE - ((U1S >> USTXC) & 0xff)) > (PDM_RESOLUTION * 4)) {
74  defaultAudioOutput();
75  }
76 }
77 
78 inline void audioOutput(const AudioOutput f) {
79  // optimized version of: Serial1.write(...);
80  for (uint8_t i = 0; i < PDM_RESOLUTION*4; ++i) {
81  U1F = pdmCode8(f+AUDIO_BIAS);
82  }
83 }
84 # endif
85 #endif
86 
87 static void startAudio() {
88 #if (EXTERNAL_AUDIO_OUTPUT == true) && (BYPASS_MOZZI_OUTPUT_BUFFER != true) // for external audio output, set up a timer running a audio rate
89  timer1_isr_init();
90  timer1_attachInterrupt(defaultAudioOutput);
91  timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP);
92  timer1_write(F_CPU / AUDIO_RATE);
94  Serial1.begin(
95  AUDIO_RATE * (PDM_RESOLUTION * 40), SERIAL_8N1,
96  SERIAL_TX_ONLY); // Note: PDM_RESOLUTION corresponds to packets of 32
97  // encoded bits However, the UART (unfortunately) adds a
98  // start and stop bit each around each byte, thus sending
99  // a total to 40 bits per audio sample per
100  // PDM_RESOLUTION.
101  // set up a timer to copy from Mozzi output_buffer into Serial TX buffer
102  timer1_isr_init();
103  timer1_attachInterrupt(esp8266_serial_audio_output);
104  // UART FIFO buffer size is 128 bytes. To be on the safe side, we keep the
105  // interval to the time needed to write half of that. PDM_RESOLUTION * 4 bytes
106  // per sample written.
107  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
108  timer1_write(F_CPU / (AUDIO_RATE * PDM_RESOLUTION));
109 #else
110  i2s_begin();
111 # if (ESP_AUDIO_OUT_MODE == PDM_VIA_I2S)
112  pinMode(2, INPUT); // Set the two unneeded I2S pins to input mode, to reduce
113  // side effects
114  pinMode(15, INPUT);
115 # endif
116  i2s_set_rate(AUDIO_RATE * PDM_RESOLUTION);
117  if (output_buffer_size == 0)
118  output_buffer_size =
119  i2s_available(); // Do not reset count when stopping / restarting
120 #endif
121 }
122 
123 
124 void stopMozzi() {
126  i2s_end();
127 #else
128  timer1_disable();
129 #endif
130  interrupts();
131 }
132 
133 #if ((ESP_AUDIO_OUT_MODE == PDM_VIA_I2S) && (PDM_RESOLUTION != 1))
134 # define AUDIOTICK_ADJUSTMENT ((output_buffer_size - i2s_available()) / PDM_RESOLUTION)
135 #else
136 # define AUDIOTICK_ADJUSTMENT (output_buffer_size - i2s_available())
137 #endif
138 
139 //// END AUDIO OUTPUT code ///////
#define PDM_VIA_SERIAL
#define ESP_AUDIO_OUT_MODE
void setupFastAnalogRead(int8_t speed)
NOTE: Code needed to set up faster than usual analog reads, e.g.
#define PDM_VIA_I2S
Definition: AudioConfigESP.h:9
#define PDM_RESOLUTION
#define AUDIO_BIAS
Definition: MozziGuts.h:229
#define EXTERNAL_DAC_VIA_I2S