Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
fe17896
Initial changes to CircularBuffer for smaller buffer sizes
tomcombriat Apr 18, 2025
98e9cc7
Started documentation of MOZZI_BUFFER_SIZE
tomcombriat Apr 18, 2025
1c46911
Changed MOZZI_BUFFER_SIZE to MOZZI_OUTPUT_BUFFER_SIZE
tomcombriat Apr 18, 2025
3d6c5ea
Added generic config
tomcombriat Apr 18, 2025
ff7b782
Modified CircularBuffer to have the buffer size as a template
tomcombriat Apr 18, 2025
ba78571
Updated MozziGuts for different buffer size
tomcombriat Apr 18, 2025
8c1a6e7
Fix Renesas compilation with MOZZI_OUTPUT_BUFFER_SIZE
tomcombriat Apr 18, 2025
9ecdd09
FixESP8266 I2S
tomcombriat Apr 19, 2025
aa967f1
Added warning messages when defining a smaller does not have an effect
tomcombriat Apr 19, 2025
04b3263
Merge branch 'master' into dev/small_buffer
tomcombriat Jan 9, 2026
78ebf73
Merge remote-tracking branch 'upstream/master' into dev/small_buffer
tomcombriat Jan 9, 2026
f7cf290
Add support for CH32X035 microcontrollers
NoNamedCat Jan 16, 2026
a034090
Refine platform detection macros: use ARDUINO_ARCH_CH32V for IS_CH32,…
NoNamedCat Jan 16, 2026
468b0ec
Ensure CH32 headers are included in generic dispatchers (config check…
NoNamedCat Jan 16, 2026
3e45eab
Merge pull request #308 from sensorium/dev/small_buffer
tomcombriat Jan 17, 2026
a621383
Increase version number
tomcombriat Jan 17, 2026
4d4f43a
Merge branch 'feat/ch32-support-standalone' of github.com:NoNamedCat/…
tomcombriat Jan 17, 2026
d7a80c7
Fix compilation for CH32
tomcombriat Jan 18, 2026
bf55f56
feat(ch32): implement non-blocking analog read support
NoNamedCat Jan 20, 2026
a0d1678
chore: enable MOZZI_ANALOG_READ_STANDARD by default for CH32
NoNamedCat Jan 20, 2026
05570d5
fix(ch32): align ADC implementation with CH32X035 SPL
NoNamedCat Jan 20, 2026
0678911
Fixed CH32X035 ADC resolution definition to 12-bit
NoNamedCat Jan 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 101 additions & 7 deletions CircularBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,113 @@ Modified from https://en.wikipedia.org/wiki/Circular_buffer
Mirroring version
On 18 April 2014, the simplified version on the Wikipedia page for power of 2 sized buffers
doesn't work - cbIsEmpty() returns true whether the buffer is full or empty.

April 2025: modified for different buffer sizes under the suggestion
of Meebleeps (https://github.com/sensorium/Mozzi/issues/281)
*/

#define MOZZI_BUFFER_SIZE 256 // do not expect to change and it to work.
// just here for forward compatibility if one day
// the buffer size might be editable

/** Circular buffer object. Has a fixed number of cells, set to 256.

/** Circular buffer object. Has a fixed number of cells, set by BUFFER_SIZE.
@tparam ITEM_TYPE the kind of data to store, eg. int, int8_t etc.
@tparam BUFFER_SIZE the size of the circular buffer
*/
template <class ITEM_TYPE>
template <class ITEM_TYPE, int16_t BUFFER_SIZE>
class CircularBuffer
{

public:
/** Constructor
*/
CircularBuffer(): start(0),end(0),s_msb(0),e_msb(0)
{
}

inline
bool isFull() {
return end == start && e_msb != s_msb;
}

inline
bool isEmpty() {
return end == start && e_msb == s_msb;
}

inline
void write(ITEM_TYPE in) {
items[end] = in;
//if (isFull()) cbIncrStart(); /* full, overwrite moves start pointer */
cbIncrEnd();
}

inline
ITEM_TYPE read() {
ITEM_TYPE out = items[start];
cbIncrStart();
return out;
}

inline
unsigned long count() {
return (num_buffers_read << COUNT_LSHIFT) + start;
}
inline
ITEM_TYPE * address() {
return items;
}

private:
ITEM_TYPE items[BUFFER_SIZE];
uint8_t start; /* index of oldest itement */
uint8_t end; /* index at which to write new itement */
uint8_t s_msb;
uint8_t e_msb;
unsigned long num_buffers_read;
static constexpr unsigned long COUNT_LSHIFT =
(BUFFER_SIZE == 256) ? 8 :
(BUFFER_SIZE == 128) ? 7 :
(BUFFER_SIZE == 64) ? 6 :
(BUFFER_SIZE == 32) ? 5 :
(BUFFER_SIZE == 16) ? 4 :
(BUFFER_SIZE == 8) ? 3 :
(BUFFER_SIZE == 4) ? 2 :
(BUFFER_SIZE == 2) ? 1 : 0;

inline
void cbIncrStart() {
start++;
if (start == BUFFER_SIZE)
{
start = 0;
s_msb ^= 1;
num_buffers_read++;
}
}

inline
void cbIncrEnd()
{
end++;
if (end == BUFFER_SIZE)
{
end = 0;
e_msb ^= 1;
}
}


};



/** Circular buffer object. Specialization for size of 256.
Note: Lot of duplication but C++ does not allow for specialization of the
function member only (partial specialization).
@tparam ITEM_TYPE the kind of data to store, eg. int, int8_t etc.
*/
template <class ITEM_TYPE>
class CircularBuffer<ITEM_TYPE, 256>
{
public:
/** Constructor
*/
Expand Down Expand Up @@ -68,7 +162,7 @@ class CircularBuffer
}

private:
ITEM_TYPE items[MOZZI_BUFFER_SIZE];
ITEM_TYPE items[256];
uint8_t start; /* index of oldest itement */
uint8_t end; /* index at which to write new itement */
uint8_t s_msb;
Expand All @@ -90,5 +184,5 @@ class CircularBuffer
end++;
if (end == 0) e_msb ^= 1;
}

};

3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ passing or external synths.
***

## Features
- Available for a wide and growing range of MCUs, with and without inbuilt DACs: Arduino Uno R3 and R4, STM32, Teensy, ESP8266, ESP32, Raspberry Pi Pico, and more.
- Available for a wide and growing range of MCUs, with and without inbuilt DACs: Arduino Uno R3 and R4, STM32, Teensy, ESP8266, ESP32, Raspberry Pi Pico, CH32, and more.
- Configurable sample rate, usually in powers of two (16384 Hz, or 32768 Hz).
- Variable control rate from 64 Hz upwards.
- Various inbuilt output modes, including 16 bit output to an external DAC.
Expand Down Expand Up @@ -69,6 +69,7 @@ If desparate, there is still a "Mozzi_1" branch in the git repository which cont
| *ESP32: that has an external DAC (only ESP32) note: Beware of vastly different pin labels across board variants* | 15 (+16) | | yes | **GPIO25 (+GPIO26)** | yes |
| *ESP32-S/C/H/P: that do not have an external DAC note: Beware of vastly different pin labels across board variants* | **15 (+16)** | | yes | | yes |
| *RP2040*: Raspberry Pi Pico and friends | **0 (+1)** | 0, 1 | | | yes |
| *CH32*: WCH CH32X035 (RISC-V) | **PA6** | PA6, PA7 | | | |

> - PWM-1: 1-pin PWM mode (`MOZZI_OUTPUT_PWM`)
> - PWM-2: 2-pin PWM mode (`MOZZI_OUTPUT_2PIN_PWM`)
Expand Down
16 changes: 16 additions & 0 deletions config/mozzi_config_documentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,22 @@
* */
#define MOZZI_AUDIO_PIN_1 FOR_DOXYGEN_ONLY

/** @ingroup config
* @def MOZZI_OUTPUT_BUFFER_SIZE
*
* @brief Audio buffer setting.
*
* For a lot of outputting modes, Mozzi is buffering the audio samples in order to be able to coop with varying loads on the processor.
* The bigger the buffer, the more able Mozzi will be to coop with big change of processor loads as the buffered values can compensate for that.
* At the same time, a bigger buffer produces a bigger latency as the time between when Mozzi produces the sample and the time it is actually outputted increases. For instance, for a long time Mozzi's buffer size was of a fixed size of 256. This produces a potential latency of 15.6 ms for a MOZZI_AUDIO_RATE of 16384, and half this value for a MOZZI_AUDIO_RATE of 32768.
* Depending on the application, this is usually not a problem but can lead to synchronisation issues in some cases (for instance when working with clocks).
* MOZZI_OUTPUT_BUFFER_SIZE can be reduced to smaller values with this config, leading to more accurate timings but potentially to glitches if the buffer runs low.
* Valid values are power of two from 256 downward (128, 64, …).
* Note that this might not have an effect in all modes/platforms combination as Mozzi is sometimes using an external buffer which is not always configurable.
*
*/
#define MOZZI_OUTPUT_BUFFER_SIZE FOR_DOXYGEN_ONLY


/***************************************** ADVANCED SETTTINGS -- External audio output ******************************************
*
Expand Down
2 changes: 2 additions & 0 deletions extras/website/_includes/boards-tested.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ td[data-sd] { border: 2px solid; background: linear-gradient(-45deg,rgba(0,0,255
<td><i>ESP32-S/C/H/P</i>: that do not have an internal DAC <i>note: Beware of vastly different pin labels across board variants</i> </td><td data-sd>15 (+16) </td><td> </td><td data-mo>yes </td><td></td><td data-st>yes</td></tr>
<tr style="border-top: 1px solid">
<td><i>RP2040</i>: Raspberry Pi Pico and friends </td><td data-sd>0 (+1) </td><td data-mo>0, 1 </td><td> - </td><td> - </td><td data-st>yes </td></tr>
<tr style="border-top: 1px solid">
<td><i>CH32</i>: WCH CH32X035 (RISC-V) </td><td data-md>PA6 </td><td data-mo>PA6, PA7 </td><td> - </td><td> - </td><td> - </td></tr>
</tbody>
</table>

Expand Down
2 changes: 1 addition & 1 deletion extras/website/index.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Your browser does not support the audio element. </audio>


## Features
- Available for a wide and growing range of MCUs, with and without inbuilt DACs: Arduino Uno R3 and R4, STM32, Teensy, ESP8266, ESP32, Raspberry Pi Pico, and more.
- Available for a wide and growing range of MCUs, with and without inbuilt DACs: Arduino Uno R3 and R4, STM32, Teensy, ESP8266, ESP32, Raspberry Pi Pico, CH32, and more.
- Configurable sample rate, usually in powers of two (16384 Hz, or 32768 Hz).
- Variable control rate from 64 Hz upwards.
- Various inbuilt output modes, including 16 bit output to an external DAC.
Expand Down
14 changes: 11 additions & 3 deletions hardware_defines.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* hardware_defines.h.h
* hardware_defines.h
*
* This file is part of Mozzi.
*
Expand Down Expand Up @@ -84,6 +84,14 @@
#define IS_RENESAS() 0
#endif

// CH32 Architecture (WCH RISC-V)
// Explicit check for CH32X035 is needed as ARDUINO_ARCH macros might not be defined by all cores/tools
#if (defined(ARDUINO_ARCH_CH32V) || defined(ARDUINO_ARCH_CH32) || defined(CH32X035))
#define IS_CH32() 1
#else
#define IS_CH32() 0
#endif

#if (defined(__arm__) && !IS_STM32MAPLE() && !IS_TEENSY3() && !IS_TEENSY4() && !IS_RP2040() && !IS_SAMD21() && !IS_MBED() && !IS_RENESAS())
#define IS_STM32DUINO() 1
#else
Expand All @@ -102,9 +110,9 @@
#define IS_ESP32() 0
#endif

#if !(IS_AVR() || IS_TEENSY3() || IS_TEENSY4() || IS_STM32MAPLE() || IS_STM32DUINO() || IS_ESP8266() || IS_SAMD21() || IS_ESP32() || IS_RP2040() || IS_MBED() || IS_RENESAS())
#if !(IS_AVR() || IS_TEENSY3() || IS_TEENSY4() || IS_STM32MAPLE() || IS_STM32DUINO() || IS_ESP8266() || IS_SAMD21() || IS_ESP32() || IS_RP2040() || IS_MBED() || IS_RENESAS() || IS_CH32())
// TODO: add an exception for MOZZI_OUTPUT_EXTERNAL_CUSTOM
#error Your hardware is not supported by Mozzi or not recognized. Edit hardware_defines.h to proceed.
#error Your hardware is not supported by Mozzi or not recognized. Edit hardware_defines.h to proceed.
#endif

// Hardware detail defines
Expand Down
8 changes: 5 additions & 3 deletions internal/MozziGuts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ template<byte BITS_IN, byte BITS_OUT, typename T> constexpr T smartShift(T value
# include "MozziGuts_impl_MBED.hpp"
#elif (IS_RENESAS())
# include "MozziGuts_impl_RENESAS.hpp"
#elif (IS_CH32())
# include "MozziGuts_impl_CH32.hpp"
#else
# error "Platform not (yet) supported. Check MozziGuts_impl_template.hpp and existing implementations for a blueprint for adding your favorite MCU."
#endif
Expand All @@ -86,7 +88,7 @@ inline void bufferAudioOutput(const AudioOutput f) {
++samples_written_to_buffer;
}
#else
CircularBuffer<AudioOutput> output_buffer; // fixed size 256
CircularBuffer<AudioOutput, MOZZI_OUTPUT_BUFFER_SIZE> output_buffer;
# define canBufferAudioOutput() (!output_buffer.isFull())
# define bufferAudioOutput(f) output_buffer.write(f)
static void CACHED_FUNCTION_ATTR defaultAudioOutput() {
Expand Down Expand Up @@ -150,7 +152,7 @@ uint16_t getAudioInput() { return audio_input; }

#if MOZZI_IS(MOZZI__LEGACY_AUDIO_INPUT_IMPL, 1)
// ring buffer for audio input
CircularBuffer<uint16_t> input_buffer; // fixed size 256
CircularBuffer<uint16_t, 256> input_buffer; // fixed size 256
#define audioInputAvailable() (!input_buffer.isEmpty())
#define readAudioInput() (input_buffer.read())
/** NOTE: Triggered at MOZZI_AUDIO_RATE via defaultAudioOutput(). In addition to the MOZZI_AUDIO_INPUT_PIN, at most one reading is taken for mozziAnalogRead(). */
Expand Down Expand Up @@ -319,4 +321,4 @@ MOZZI_DEPRECATED("n/a", "Sketch has audioOutput() function, although external ou
#if !MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_EXTERNAL_CUSTOM)
// TODO: This won't work without a rename:
//MOZZI_DEPRECATED("n/a", "Sketch has canBufferAudioOutput() function, although custom external output is not configured.") bool canBufferAudioOutput() {};
#endif
#endif
Loading
Loading