Skip to content

Commit

Permalink
Start moving MozziGuts over the the new config.
Browse files Browse the repository at this point in the history
Commit known to be broken.

The larger part of this is actually moving around / merging lots of (duplicated) information.
  • Loading branch information
tfry-git committed Nov 13, 2023
1 parent f837cf1 commit 1c42eec
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 205 deletions.
46 changes: 38 additions & 8 deletions MozziConfigExample.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,41 @@
* currently used by the oscillators. You can look at the TimerOne library for more info about how interrupt rate and pwm resolution relate.
*
* @section avr_2pin_pwm MOZZI_OUTPUT_2PIN_PWM
* For MOZZI_OUTPUT_2PIN_PWM, Timer 2 is used in addition to Timer 1. Output is split across two pins (again, both connected to Timer 1), with each
* outputting 7 bits for a total of 14. Add signals through a 3.9k resistor on the "high" pin and 499k resistor on "low" pin.
* Use 0.5% resistors or select the most accurate from a batch. As discussed on http://www.openmusiclabs.com/learning/digital/pwm-dac/dual-pwm-circuits/
* In this mode, output is split across two pins (again, both connected to Timer 1), with each outputting 7 bits for a total of 14. This allows for
* much better dynamic range, providing much more definition than can be achieved using @ref avr_pwm , while using
* only modestly more processing power. Further, it allows for a much higher PWM carrier rate can be much higher (125 kHz by default; see @ref
* MOZZI_PWM_RATE), which is well beyond the audible range.
*
* On the downside, this mode requires an extra hardware timer (Timer2 in addition to Timer1), which may increase compatibility
* problems with other Arduino libraries that also require a timer. Further, a more elaborate hardware setup is needed, making it less convenient
* for rapid prototyping:
*
* In hardware, add the two signals through a 3.9k resistor on the "high" pin and 499k resistor on "low" pin.
* Use 0.5% resistors or select the most accurate from a batch. It is further recommended to place a 4.7nF capacitor between the summing junction
* of the resistors and ground. This is discussed in much more detail on http://www.openmusiclabs.com/learning/digital/pwm-dac/dual-pwm-circuits/
* Also, there are higher quality output circuits are on the site.
*
* The default pinout in this mode is:
* On the classic Arduino Uno, the default pinout in this mode is:
* - Pin 9 (high bits) and Pin 10 (low bits) -> configurable using MOZZI_AUDIO_PIN_1 and MOZZI_AUDIO_PIN_1_LOW
* For pinouts on other boards, refer to config/known_16bit_timers.
*
* Here is table of the default pins on some other boards. Rows with an x on it have actually been tested (and importantly, the outcome recoreded;
* input welcome on further boards.)
*
* resistor.....3.9k......499k \n
* x................9..........10...............Arduino Uno \n
* x................9..........10...............Arduino Duemilanove \n
* x................9..........10...............Arduino Nano \n
* x................9..........10...............Arduino Leonardo \n
* x................9..........10...............Ardweeny \n
* x................9..........10...............Boarduino \n
* x...............11.........12...............Freetronics EtherMega \n
* .................11.........12...............Arduino Mega \n
* .................14.........15...............Teensy \n
* .............B5(14)...B6(15)...........Teensy2 \n
* x...........B5(25)...B6(26)...........Teensy2++ \n
* .................13.........12...............Sanguino \n
*
* For pinouts on other AVR boards, config/known_16bit_timers might contain some hints.
*
* Rate of the PWM output can be controlled separately from MOZZI_AUDIO_RATE, and is much higher (125kHz), by default: MOZZI_PWM_RATE.
*
Expand All @@ -242,10 +269,13 @@
* @def MOZZI_PWM_RATE
*
* <em>Only for MOZZI_AUDIO_MODE s MOZZI_OUTPUT_PWM and MOZZI_OUTPUT_2PIN_PWM</em>. On some platforms, the rate at which PWM signals are repeated may be higher
* than that at with audio signals are produced (i.e. MOZZI_AUDIO_RATE). E.g. fro MOZZI_OUTPUT_PWM on the classic Arduino, the pwm defaults to 32768 while the audio rate defaults to 16384.
* than that at with audio signals are produced (i.e. MOZZI_AUDIO_RATE). E.g. for MOZZI_OUTPUT_PWM on the classic Arduino, the pwm defaults to 32768 while the
* audio rate defaults to 16384. The reasoning behind this is that 16384 Hz audio rate turned out to be te most useful compromise - in most casses - between
* output quality, and available computing power. However, output at that rate produced high-frequency whine, audible to some people, which could be mitigated
* by the higher PWM rate.
*
* This improves the signal quality at less cost than doubling the audio rate itself. However, increasing this too far will limit the dynamic resolution of the samples that can be
* writte to the output pin(s): 2 ^ (output bits) * MOZZI_PWM_RATE cannot be higher than the CPU frequency!
* In other words, increasing this improves the signal quality at less cost than doubling the audio rate itself. However, increasing this too far will limit the dynamic resolution of the samples that can be
* written to the output pin(s): 2 ^ (output bits) * MOZZI_PWM_RATE cannot be higher than the CPU frequency!
*/

/** @ingroup core
Expand Down
210 changes: 14 additions & 196 deletions MozziGuts.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,175 +29,9 @@

#include "mozzi_analog.h"

#if not defined (CONTROL_RATE)
/** @ingroup core
Control rate setting.
Mozzi's CONTROL_RATE sets how many times per second updateControl() is called.
CONTROL_RATE has a default of 64 Hz, but it can be changed at the top of your sketch,
(before the \#includes), for example: \#define CONTROL_RATE 256.
It is useful to have CONTROL_RATE set at a power of 2 (such as 64,128,256 etc),
to have exact timing of audio and control operations.
Non-power-of-2 CONTROL_RATE can cause glitches due to audio and control
events not lining up precisely. If this happens a power of two CONTROL_RATE might solve it.
Try to keep CONTROL_RATE low, for efficiency, though higher rates up to about 1000
can sometimes give smoother results, avoiding the need to interpolate
sensitive variables at audio rate in updateAudio().
*/
#define CONTROL_RATE 64
#endif



/** @ingroup core
Used to set AUDIO_MODE to STANDARD, STANDARD_PLUS, or HIFI.
STANDARD / STANDARD_PLUS
---------------
Use \#define AUDIO_MODE STANDARD_PLUS in Mozzi/config.h to select this
output configuration, which is nearly 9 bit sound (-244 to 243) at 16384 Hz sample rate (AUDIO_RATE) and
32768 Hz PWM rate. It uses Timer 1 for PWM and the sample updating routine (as an interrupt).
STANDARD is obsolete now, replaced by STANDARD_PLUS which is the default audio mode.
STANDARD mode uses 16384 Hz PWM rate with an output interrupt at the same frequency.
Some people can hear the PWM carrier frequency as an annoying whine.
STANDARD_PLUS mode uses 32768 Hz PWM rate, so the PWM carrier is out of hearing range.
In this mode every alternate interrupt is used for the sample update (unless you /#define AUDIO_RATE 32768 in mozzi_config.h),
which makes it slightly less efficient than STANDARD, but almost always better.
Advantages: Only uses one timer for audio, and one output pin.
Disadvantages: low dynamic range.
Below is a list of the Digital Pins used by Mozzi for STANDARD and STANDARD_PLUS audio out on different boards.
Those which have been tested and reported to work have an x.
Feedback about others is welcome.
Model | Pin | Tested
----- | --- | ------
Arduino Uno | 9 | yes
Arduino Duemilanove | 9 | yes
Arduino Nano | 9 | yes
Arduino Pro Mini | 9 | yes
Arduino Leonardo | 9 | yes
Arduino Mega | 11 | yes
Freetronics EtherMega | 11 | yes
Ardweeny | 9 | yes
Boarduino | 9 | yes
Teensy | 14 | -
Teensy2 | B5 | yes
Teensy2++ | B5(25) | yes
Teensy 3.0 3.1 LC 3.2 | DAC/D | yes
Teensy 3.4, 3.5 | DAC/D | -
Teensy 4.0 4.1 | A8 | yes
Gemma M0 | A0 | yes
Adafruit Playground Express | Built in Speaker | yes
Sanguino | 13 | -
STM32duino (see "Hardware specific notes", below) | PB8 | yes
ESP8266 *see details in README* | GPIO2 | yes
RP2040 | 0 | yes
On Teensy 3.* STANDARD and STANDARD_PLUS are the same, providing 16384Hz sample rate and 12 bit resolution on pin A14/ADC.
The Teensy 3.* DAC output does not rely on PWM.
@ingroup core
Used to set AUDIO_MODE to HIFI.
HIFI for AVR and STM32 (not for Teensy 3.*)
----
Use \#define AUDIO_MODE HIFI in Mozzi/config.h to set the audio mode to HIFI for output 14 bit sound at 16384 Hz sample rate and 125kHz PWM rate.
The high PWM rate of HIFI mode places the carrier frequency beyond audible range.
Also, 14 bits of dynamic range in HIFI mode provides more definition than the nearly 9 bits in STANDARD_PLUS mode.
HIFI mode takes about the same amount of processing time as STANDARD_PLUS mode, and should sound clearer and brighter.
However, it requires an extra timer to be used on the Arduino, which could increase the chances of
conflicts with other libraries or processes if they rely on Timer 2.
Timer 1 is used to provide the PWM output at 125kHz.
Timer 2 generates an interrupt at AUDIO_RATE 16384 Hz, which sets the Timer1 PWM levels.
HIFI mode uses 2 output pins, and sums their outputs with resistors, so is slightly less convenient for
rapid prototyping where you could listen to STANDARD_PLUS mode by connecting the single output pin
directly to a speaker or audio input (though a resistor of about 100 ohms is recommended).
The resistors needed for HIFI output are 3.9k and 499k, with 0.5% or better tolerance.
If you can only get 1% resistors, use a multimeter to find the most accurate.
Use two 1M resistors in parallel if you can't find 499k.
On 328 based Arduino boards, output is on Timer1, with the high byte on Pin 9 and low byte on Pin 10.
Add the signals through a 3.9k resistor on high byte pin (9) and 499k resistor on low byte pin (10).
Also, a 4.7nF capacitor is recommended between the summing junction of the resistors and ground.
This dual PWM technique is discussed on http://www.openmusiclabs.com/learning/digital/pwm-dac/dual-pwm-circuits/
Also, there are higher quality output circuits are on the site.
Advantages: should be higher quality sound than STANDARD_PLUS mode. Doesn't need a notch filter on
the audio signal (like STANDARD which is now obsolete) because the carrier frequency is out of hearing range.
Disadvantages: requires 2 pins, 2 resistors and a capacitor, so it's not so quick to set up compared
to a rough, direct single-pin output in STANDARD_PLUS mode.
Pins and where to put the resistors on various boards for HIFI mode.
Boards tested in HIFI mode have an x, though most of these have been tested in STANDARD_PLUS mode
and there's no reason for them not to work in HIFI (unless the pin number is wrong or something).
Any reports are welcome. \n
resistor.....3.9k......499k \n
x................9..........10...............Arduino Uno \n
x................9..........10...............Arduino Duemilanove \n
x................9..........10...............Arduino Nano \n
x................9..........10...............Arduino Leonardo \n
x................9..........10...............Ardweeny \n
x................9..........10...............Boarduino \n
x...............11.........12...............Freetronics EtherMega \n
.................11.........12...............Arduino Mega \n
.................14.........15...............Teensy \n
.............B5(14)...B6(15)...........Teensy2 \n
x...........B5(25)...B6(26)...........Teensy2++ \n
.................13.........12...............Sanguino \n
HIFI is not available/not required on Teensy 3.* or ARM.
*/

//enum audio_modes {STANDARD,STANDARD_PLUS,HIFI};
#define STANDARD 0
#define STANDARD_PLUS 1
#define HIFI 2

//enum audio_channels {MONO,STEREO,...};
#define MONO 1
#define STEREO 2

#include "mozzi_config.h" // User can change the config file to set audio mode

#if (AUDIO_MODE == STANDARD) && (AUDIO_RATE == 32768)
#error AUDIO_RATE 32768 does not work when AUDIO_MODE is STANDARD, try setting the AUDIO_MODE to STANDARD_PLUS in Mozzi/mozzi_config.h
#endif

#if (STEREO_HACK == true)
#warning Use of STEREO_HACK is deprecated. Use AUDIO_CHANNELS STEREO, instead.
#define AUDIO_CHANNELS STEREO
#endif
#if !defined(AUDIO_CHANNELS)
#define AUDIO_CHANNELS MONO
#endif
#include "internal/config_check_generic.h"

#define CLOCK_TICKS_PER_AUDIO_TICK (F_CPU / AUDIO_RATE)


#if AUDIO_RATE == 16384
#define AUDIO_RATE_AS_LSHIFT 14
#define MICROS_PER_AUDIO_TICK 61 // 1000000 / 16384 = 61.035, ...* 256 = 15625
#elif AUDIO_RATE == 32768
#define AUDIO_RATE_AS_LSHIFT 15
#define MICROS_PER_AUDIO_TICK 31 // = 1000000 / 32768 = 30.518, ...* 256 = 7812.6
#endif

// for compatibility with old (local) versions of mozzi_config.h
#if !defined(EXTERNAL_AUDIO_OUTPUT)
#define EXTERNAL_AUDIO_OUTPUT false
#endif

#if (EXTERNAL_AUDIO_OUTPUT != true)
#if IS_TEENSY3()
Expand Down Expand Up @@ -241,6 +75,7 @@ extern int audio_out_1, audio_out_2;

#include "AudioOutput.h"

// TODO Mozzi 2.0: These typedef probably obsolete?
// common numeric types
typedef unsigned char uchar;
typedef unsigned int uint;
Expand All @@ -264,16 +99,8 @@ Sets up the timers for audio and control rate processes, storing the timer
registers so they can be restored when Mozzi stops. startMozzi() goes in your sketch's
setup() routine.
Contrary to earlier versions of Mozzi, this version does not take over Timer 0, and thus Arduino
functions delay(), millis(), micros() and delayMicroseconds() remain usable in theory. That said,
you should avoid these functions, as they are slow (or even blocking). For measuring time, refer
to mozziMircos(). For delaying events, you can use Mozzi's EventDelay() unit instead
(not to be confused with AudioDelay()).
In STANDARD mode, startMozzi() starts Timer 1 for PWM output and audio output interrupts,
and in STANDARD_PLUS and HIFI modes, Mozzi uses Timer 1 for PWM and Timer2 for audio interrupts.
The audio rate defaults to 16384 Hz, but you can experiment with 32768 Hz by changing AUDIO_RATE in mozzi_config.h.
This function intializes the timer(s) needed to move audio samples to the output according to the
configured @ref MOZZI_AUDIO_MODE .
@param control_rate_hz Sets how often updateControl() is called. It must be a power of 2.
If no parameter is provided, control_rate_hz is set to CONTROL_RATE,
Expand Down Expand Up @@ -303,22 +130,12 @@ reading sensors.
As it is, stopMozzi restores all the Timers used by Mozzi to their previous
settings. Another scenario which could be easily hacked in MozziGuts.cpp could
involve individually saving and restoring particular Timer registers depending
on which one(s) are required for other tasks. */
void stopMozzi();
on which one(s) are required for other tasks.

/** @ingroup core
Obsolete function, use stopMozzi() instead.
@note This function is not actually implemented on all platforms.
*/
void pauseMozzi();
void stopMozzi();

//TB2017-19
/** @ingroup core
Obsolete function, use startMozzi() instead.
Restores Mozzi audio and control interrupts, if they have been temporarily
disabled with pauseMozzi().
*/
void unPauseMozzi();


/** @ingroup core
Expand All @@ -327,6 +144,8 @@ AUDIO_RATE of 16384 Hz, so to keep things running smoothly, avoid doing any
calculations here which could be done in setup() or updateControl().
@return an audio sample. In STANDARD modes this is between -244 and 243 inclusive.
In HIFI mode, it's a 14 bit number between -16384 and 16383 inclusive.
TODO: Update documentation
*/
AudioOutput_t updateAudio();

Expand All @@ -342,7 +161,7 @@ void updateControl();
/** @ingroup core
This is required in Arduino's loop(). If there is room in Mozzi's output buffer,
audioHook() calls updateAudio() once and puts the result into the output
buffer. Also, if \#define USE_AUDIO_INPUT true is in Mozzi/mozzi_config.h,
buffer. Also, if \@ref MOZZI_AUDIO_INPUT is enabled in the config,
audioHook() takes care of moving audio input from the input buffer so it can be
accessed with getAudioInput() in your updateAudio() routine.
If other functions are called in loop() along with audioHook(), see if
Expand All @@ -358,10 +177,9 @@ void audioHook();

/** @ingroup analog
This returns audio input from the input buffer, if
\#define USE_AUDIO_INPUT true is in the Mozzi/mozzi_config.h file.
The pin used for audio input is set in Mozzi/mozzi_config.h with
\#define AUDIO_INPUT_PIN 0 (or other analog input pin).
The audio signal needs to be in the range 0 to 5 volts.
\@ref MOZZI_AUDIO_INPUT is enabled in the config (see also the related option MOZZI_AUDIO_INPUT_PIN).
The audio signal needs to be in the range 0 to VCC volts (i.e. 5 volts on Arduino Uno R3).
Circuits and discussions about biasing a signal
in the middle of this range can be found at
http://electronics.stackexchange.com/questions/14404/dc-biasing-audio-signal
Expand All @@ -371,7 +189,7 @@ A circuit and instructions for amplifying and biasing a microphone signal can be
http://www.instructables.com/id/Arduino-Audio-Input/?ALLSTEPS
@return audio data from the input buffer
*/
#if (USE_AUDIO_INPUT == true)
#if !MOZZI_IS(MOZZI_AUDIO_INPUT, MOZZI_AUDIO_INPUT_NONE)
int getAudioInput();
#endif

Expand Down
15 changes: 15 additions & 0 deletions Readme_Mozzi_2_0.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,18 @@ all new
- MOZZI_ANALOG_READS
- MOZZI_COMPATIBILITY_LEVEL



Other removed stuff:
- pauseMozzi() - was still declared but not defined -> not usable, anyway
- unpauseMozzi() - was still declared but not defined -> not usable, anyway



Documentation bits that still need to find a new home (many other bits were moved around, many, many duplicates merged into a common place, and seom obsoleted bits discarded):

Contrary to earlier versions of Mozzi, this version does not take over Timer 0, and thus Arduino
functions delay(), millis(), micros() and delayMicroseconds() remain usable in theory. That said,
you should avoid these functions, as they are slow (or even blocking). For measuring time, refer
to mozziMircos(). For delaying events, you can use Mozzi's EventDelay() unit instead
(not to be confused with AudioDelay()).
25 changes: 24 additions & 1 deletion internal/config_check_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@
#endif

#if not defined(MOZZI_AUDIO_CHANNELS)
#if (MOZZI_COMPATIBILITY_LEVEL <= MOZZI_COMPATIBILITY_1_1) && (STEREO_HACK == true)
#warning Use of STEREO_HACK is deprecated. Use AUDIO_CHANNELS STEREO, instead.
#define MOZZI_AUDIO_CHANNELS MOZZI_STEREO
#else
#define MOZZI_MONO
#endif
#endif

//MOZZI_AUDIO_MODE -> hardware specific
//MOZZI_AUDIO_RATE -> hardware specific
Expand Down Expand Up @@ -88,7 +93,22 @@ static_assert(MOZZI_AUDIO_BITS <= (4*sizeof(AudioOutputStorage_t)), "Configured
#define MOZZI_AUDIO_BITS_OPTIMISTIC MOZZI_AUDIO_BITS
#endif


// TODO: Rename these defines
#if MOZZI_AUDIO_RATE == 8192
#define AUDIO_RATE_AS_LSHIFT 13
#define MICROS_PER_AUDIO_TICK 122
#if MOZZI_AUDIO_RATE == 16384
#define AUDIO_RATE_AS_LSHIFT 14
#define MICROS_PER_AUDIO_TICK 61 // 1000000 / 16384 = 61.035, ...* 256 = 15625
#elif MOZZI_AUDIO_RATE == 32768
#define AUDIO_RATE_AS_LSHIFT 15
#define MICROS_PER_AUDIO_TICK 31 // = 1000000 / 32768 = 30.518, ...* 256 = 7812.6
#elif MOZZI_AUDIO_RATE == 65336
#define AUDIO_RATE_AS_LSHIFT 16
#define MICROS_PER_AUDIO_TICK 15
#else
#error Whoopsie, not LSHIFT defined for this audio rate. Please report and/or fix
#endif


/// Step 5: Patch up some backwards compatibility issues as far as config-related
Expand All @@ -97,4 +117,7 @@ static_assert(MOZZI_AUDIO_BITS <= (4*sizeof(AudioOutputStorage_t)), "Configured
#define CONTROL_RATE MOZZI_CONTROL_RATE
#endif




#endif

0 comments on commit 1c42eec

Please sign in to comment.