Skip to content

Commit

Permalink
Finish "outline" for config options (generic, and AVR, only for now)
Browse files Browse the repository at this point in the history
  • Loading branch information
tfry-git committed Nov 13, 2023
1 parent 571e460 commit 80c4908
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 36 deletions.
2 changes: 2 additions & 0 deletions AudioOutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* 2. A platform-specific timer is triggered at audio rate (usually), takes a sample from the output buffer and sends it to audioOutput().
*
* 3. The audioOutput() function - usually predefined inside Mozzi - takes care of sending the sample to the hardware.
* // TODO refer to @see external_audio for most of this, instead.
*
* This basic output pipeline can be customized in several ways. First, defining EXTERNAL_AUDIO_OUTPUT to true in mozzi_config.h will allow you to define your own audioOutput()
* fuction. The library ships with some sample sketches for output to external DACs using this mechanism.
Expand Down Expand Up @@ -46,6 +47,7 @@
#define AudioOutputStorage_t int

#if IS_AVR() && ((AUDIO_MODE == STANDARD_PLUS) || (AUDIO_MODE == STANDARD))
// TODO: remove this specialisation -> see MOZZI_AUDIO_BITS_OPTIMISTIC
#define SCALE_AUDIO(x,bits) (bits > 8 ? (x) >> (bits - 8) : (x) << (8 - bits))
#define SCALE_AUDIO_NEAR(x,bits) (bits > 9 ? (x) >> (bits - 9) : (x) << (9 - bits))
#define CLIP_AUDIO(x) constrain((x), -244,243)
Expand Down
85 changes: 61 additions & 24 deletions MozziConfigExample.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* TODO: Fix and complete Doxygen coverage
*/

#include <MozziConfigValues.h> // needed for the named option values

/** @ingroup core
* @def MOZZI_COMPATIBILTY_LEVEL
*
Expand Down Expand Up @@ -48,16 +50,17 @@
* hardware setup is correct. Similarly, if you observe problems running your "real" sketch, it is often a good idea ot test your sketch with the default audio mode,
* too (by leaving this option, and preferrably all others, unset).
*
* TODO: link to specific documentation for each option/platform, and/or spell out, what is supported, where
* TODO: link to specific documentation for each option/platform, here, and/or spell out, what is supported, where
*
* Supported values:
* - MOZZI_OUTPUT_PWM Output using pulse width modulation (PWM) on a GPIO pin. This is the default on most platforms.
* On the Arduino Uno (more generally ATMEGA328P), this allows for a sample resolution of 488 (almost 9 bits) on pin 9.
* Usable pins and resolution will be different on other boards.
* - MOZZI_OUTPUT_2PIN_PWM Output using pulse width modulation on two GPIO pins, where one pin represents the lower bits, and the other the higer bits of the sample.
* On the Aduino Uno, this allows for 14 bits of resolution on pins 9 (low) and 10 (high). For further information (wiring etc.) see TODO add ref.
* - MOZZI_OUTPUT_EXTERNAL Output is not controlled by Mozzi itself, but left to the user sketch. This setting allows to completely customize the audio output, e.g.
* for connecting to external DACs. For more detail, @see AudioOuput
* On the Aduino Uno, this allows for 14 bits of resolution on pins 9 (low) and 10 (high). For further information (wiring etc.) see @ref hardware_avr_2pin.
* - MOZZI_OUTPUT_EXTERNAL_TIMED Output is not controlled by Mozzi itself, but left to the user sketch. This setting allows to completely customize the audio output, e.g.
* for connecting to external DACs. For more detail, see @ref external_audio
* - MOZZI_OUTPUT_EXTERNAL_CUSTOM As above, but additionally bypassing Mozzi's sample buffer. For more detail, see @ref external_audio
* - MOZZI_OUTPUT_PDM_VIA_I2S Output pulse density modulated (PDM) samples via a (hardware) I2S interface (without a DAC connected to it).
* - MOZZI_OUTPUT_PDM_VIA_SERIAL Output pulse density modulated (PDM) samples via a hardware serial interface.
* - MOZZI_OUTPUT_I2S_DAC Output samples to a PT8211 (or compatible) DAC connected to a hardware I2S interface.
Expand All @@ -82,7 +85,7 @@
*
* @note At the time of this writing, only MOZZI_MONO and MOZZI_STEREO are supported. The value of
* MOZZI_MONO is 1 and the value of MOZZI_STEREO is 2, so future extensions are also expected
* to set this to the number of available channels. */
* to set this to the number of available channels, and it's ok to use numerical comparison. */
//#define MOZZI_AUDIO_CHANNELS MOZZI_STEREO


Expand Down Expand Up @@ -162,7 +165,7 @@
* This mode implies that MOZZI_ANALOG_READ s are enabled and supported. You may have to call setupFastAnalogReads(FASTEST_ADC)
* after setupMozzi(), when using this.
*
* Further reading and config: @see getAudioInput() @see MOZZI_AUDIO_INPUT_PIN
* Further reading and config: @ref getAudioInput() @ref MOZZI_AUDIO_INPUT_PIN
*/
//#define MOZZI_AUDIO_INPUT MOZZI_AUDIO_INPUT_STANDARD

Expand Down Expand Up @@ -193,15 +196,16 @@
/** @ingroup hardware
* @page hardware_avr Mozzi on classic Arduino, Teensy (2.x and 3.x), Arduino Mega, and other 8 bit "AVR"/ATMEGA architecture boards
*
* The following audio modes (@see MOZZI_AUDIO_MODE) are currently supported on this hardware. In all cases, Timer 1 is claimed, and
* The following audio modes (see @ref MOZZI_AUDIO_MODE) are currently supported on this hardware. In all cases, Timer 1 is claimed, and
* is not available for any other purpose:
* - MOZZI_OUTPUT_PWM
* - MOZZI_OUTPUT_2PIN_PWM
* - MOZZI_OUTPUT_EXTERNAL
* - MOZZI_OUTPUT_EXTERNAL_TIMED
* - MOZZI_OUTPUT_EXTERNAL_CUSTOM
*
* In all cases, Timer 1 is claimed, and is not available for any other purpose.
*
* @section MOZZI_OUTPUT_PWM
* @section avr_pwm MOZZI_OUTPUT_PWM
* For MOZZI_OUTPUT_PWM, output is restricted to pins that are hardware-attached to Timer 1, but can be configured
* within this tight limit. In particular, the default setup on the
* Arduino UNO is:
Expand All @@ -214,7 +218,7 @@
* The available sample resolution is 488, i.e. almost 9 bits, providing some headroom above the 8 bit table resolution
* currently used by the oscillators. You can look at the TimerOne library for more info about how interrupt rate and pwm resolution relate.
*
* @section MOZZI_OUTPUT_2PIN_PWM
* @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/
Expand All @@ -226,11 +230,11 @@
*
* Rate of the PWM output can be controlled separately from MOZZI_AUDIO_RATE, and is much higher (125kHz), by default: MOZZI_PWM_RATE.
*
* The default sample resolution is 7 bits per pin, for a total of 14 bits. This can be configured within hardware limits (@see MOZZI_PWM_RATE) using
* The default sample resolution is 7 bits per pin, for a total of 14 bits. This can be configured within hardware limits (@ref MOZZI_PWM_RATE) using
* MOZZI_AUDIO_BITS_PER_CHANNEL, but beware that increasing this will require even more accuracy in our output resistors (see the linked documentation, above).
*
* @section MOZZI_OUTPUT_PWM
* @see AudioOutput
* @section avr_external MOZZI_OUTPUT_EXTERNAL_TIMED and MOZZI_OUTPUT_EXTERNAL_CUSTOM
* See @ref external_audio
*/


Expand All @@ -244,24 +248,57 @@
* writte to the output pin(s): 2 ^ (output bits) * MOZZI_PWM_RATE cannot be higher than the CPU frequency!
*/

/** @ingroup core
* @def MOZZI_AUDIO_BITS_PER_CHANNEL
*
* <em>Only for MOZZI_AUDIO_MODE MOZZI_OUTPUT_2PIN_PWM</em>. Sample resolution per channel to use in 2 pin output, given in bits (i.e. total resolution is twice as much).
* Defaults to 7 bits per channel. Note that increasing this requires very, very well matched output resistors.
*
* See @ref hardware_avr for a more detailed description.
*/





/***************************************** ADVANCED SETTTINGS -- External audio output ******************************************
*
* The settings in the following section applies to MOZZI_OUTPUT_EXTERNAL_TIMED, and MOZZI_OUTPUT_EXTERNAL_CUSTOM, only.
*
********************************************************************************************************************************/




/// TODO: settings bits that still need to end up in their proper section, below

/** @ingroup hardware
* @page external_audio External audio output
*
* <em>Only for MOZZI_AUDIO_MODE s MOZZI_OUTPUT_EXTERNAL_TIMED and MOZZI_OUTPUT_EXTERNAL_CUSTOM</em>. Most (all?) platforms support
* output using an "external" function. When using this option, you will need to provide a suitable definition for audioOutput() in
* your own sketch, yourself. Some understanding of the general Mozzi audio output architecture may be recommendable, when using this
* mode: See @ref AudioOutput .
*
* In the more simple case (MOZZI_OUPUT_EXTERNAL_TIMED), Mozzi will still take care of buffering the samples, and calling this function
* at audio rate (hence "timed"). This generally involves use of a timer, which should be detailed in the @ref hardware details for
* your platform.
*
* Should you desire even more control - perhaps because your board, or your external DAC already comes with a rate controlled DMA buffer -
* using MOZZI_OUPUT_EXTERNAL_CUSTOM also bypasses Mozzis sample buffer. In addition to audioOutput(), you will then need to provide
* a definition for canBufferAudioOutput(), which will control the rate at which samples are produced. In essence, whenever
* canBufferAudioOutput() returns true, Mozzi will call updateAudio(), and pass the produced sample to audioOutput(), unbuffered. It is
* entirely your job to make sure that this actually happens at MOZZI_AUDIO_RATE, and / or an appropriate buffer gets used.
*
* One additional configuration setting is MOZZI_AUDIO_BITS, which defaults to 16 bits for this mode, but might be set higher, if your
* hardware supports it.
*/


/** @ingroup core
* @def MOZZI_AUDIO_BITS
Only used when EXTERNAL_AUDIO_OUTPUT is set to true: The resolution to use for audio samples, internally. You will usually set this to match the
output resolution of your DAC. 16 is the default value, here. Note that 16 bits is also the maximum currently supported on AVR. */
//#define EXTERNAL_AUDIO_BITS 16



*
* Output resolution of audio samples. In most cases you should leave this value untouched (for the defaults that get applied, see @ref hardware .
* However, for MOZZI_AUDIO_MODE s MOZZI_OUTPUT_EXTERNAL_TIMED and MOZZI_OUTPUT_EXTERNAL_CUSTOM you way wish to customize the default value
* of 16 bits.
*
* @note
* At the time of this writng single audio samples are stored as "int", unconditionally. This limits MOZZI_AUDIO_BITS to a maximumg of 16 bits on
* some 8 bit boards!
*/
//#define MOZZI_AUDIO_BITS 16
11 changes: 6 additions & 5 deletions MozziConfigValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ TODO: Fix documentation
// We try to use distinct values as much as possible so we can catch semantic errors like "#define MOZZI_AUDIO_MODE MOZZI_STEREO"
#define MOZZI_OUTPUT_PWM 101
#define MOZZI_OUTPUT_2PIN_PWM 102
#define MOZZI_OUTPUT_EXTERNAL 103
#define MOZZI_OUTPUT_PDM_VIA_I2S 104
#define MOZZI_OUTPUT_PDM_VIA_SERIAL 105
#define MOZZI_OUTPUT_I2S_DAC 106
#define MOZZI_OUTPUT_INTERNAL_DAC 107
#define MOZZI_OUTPUT_EXTERNAL_TIMED 103
#define MOZZI_OUTPUT_EXTERNAL_CUSTOM 104
#define MOZZI_OUTPUT_PDM_VIA_I2S 105
#define MOZZI_OUTPUT_PDM_VIA_SERIAL 106
#define MOZZI_OUTPUT_I2S_DAC 107
#define MOZZI_OUTPUT_INTERNAL_DAC 108

#define MOZZI_AUDIO_INPUT_DISABLED 201
#define MOZZI_AUDIO_INPUT_STANDARD 202
Expand Down
31 changes: 26 additions & 5 deletions internal/config_check_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
#ifndef MOZZI_CONFIG_CHECK_GENERIC_H
#define MOZZI_CONFIG_CHECK_GENERIC_H

#include <MozziConfigValues.h> // in case not user-included

//// Step 1: Apply missing defaults for generic config options (not hardware specific)
//// Step 1: Apply missing defaults for generic config options (not the hardware specific ones)
#if not defined(MOZZI_COMPATIBILITY_LEVEL)
#define MOZZI_COMPATIBILITY_LEVEL MOZZI_COMPATIBILITY_2_0
#endif
Expand Down Expand Up @@ -38,6 +39,7 @@
//MOZZI_AUDIO_PIN_2_LOW -> hardware specific



/// Step 2: Include the hardware specific checks-and-defaults-header
#if IS_AVR()
#include "config_checks_avr.h"
Expand All @@ -46,6 +48,14 @@

#endif


/// Step 2b: Minimal special handling for MOZZI_OUTPUT_EXTERNAL
#if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_EXTERNAL) && !defined(MOZZI_AUDIO_BITS)
#define MOZZI_AUDIO_BITS 16
#endif



/// Step 3: Apply various generic checks that make sense on more than one platform
MOZZI_CHECK_POW2(MOZZI_AUDIO_RATE)
MOZZI_CHECK_POW2(MOZZI_CONTROL_RATE)
Expand All @@ -62,15 +72,26 @@ MOZZI_CHECK_POW2(MOZZI_CONTROL_RATE)
#error "MOZZI_AUDIO_CHANNELS outside of (currently) supported range"
#endif

// Hardware-specific checks file should have more narrow checks for most options, below, but is not required to:
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM, MOZZI_OUTPUT_EXTERNAL,MOZZI_OUTPUT_PDM_VIA_I2S, MOZZI_OUTPUT_PDM_VIA_SERIAL, MOZZI_OUTPUT_I2S_DAC, MOZZI_OUTPUT_INTERNAL_DAC)
// Hardware-specific checks file should have more narrow checks for most options, below, but is not required to, so let's check for anything that is wildly out of scope:
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM, MOZZI_OUTPUT_EXTERNAL_TIMED, MOZZI_OUTPUT_EXTERNAL_CUSTOM, MOZZI_OUTPUT_PDM_VIA_I2S, MOZZI_OUTPUT_PDM_VIA_SERIAL, MOZZI_OUTPUT_I2S_DAC, MOZZI_OUTPUT_INTERNAL_DAC)
MOZZI_CHECK_SUPPORTED(MOZZI_ANALOG_READ, MOZZI_ANALOG_READ_NONE, MOZZI_ANALOG_READ_STANDARD)
static_assert(MOZZI_AUDIO_BITS <= (4*sizeof(AudioOutputStorage_t)), "Configured MOZZI_AUDIO_BITS is too large for the internal storage type");



/// Step 4: Init Read-only defines that depend on other values
#if !defined(MOZZI_AUDIO_BIAS)
#define MOZZI_AUDIO_BIAS ((uint16_t) 1<<(MOZZI_AUDIO_BITS-1))
#endif

#if !defined(MOZZI_AUDIO_BITS_OPTIMISTIC)
#define MOZZI_AUDIO_BITS_OPTIMISTIC MOZZI_AUDIO_BITS
#endif


// TODO: much more


/// Step 4: Patch up some backwards compatibility issues as far as config-related
/// Step 5: Patch up some backwards compatibility issues as far as config-related
#if MOZZI_COMPATIBILITY_LEVEL < MOZZI_COMPATIBILITY_LATEST
#define AUDIO_RATE MOZZI_AUDIO_RATE
#define CONTROL_RATE MOZZI_CONTROL_RATE
Expand Down
60 changes: 58 additions & 2 deletions internal/config_checks_avr.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,66 @@
#define MOZZI_ANALOG_READ MOZZI_ANALOG_READS_STANDARD
#endif

/// TODO much more
// Pins for regular PWM output
#if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM)
# if !defined(MOZZI_AUDIO_PIN_1)
#define MOZZI_AUDIO_PIN_1 TIMER1_A_PIN
# endif
# if (MOZZI_AUDIO_CHANNELS > 1) && !defined(MOZZI_AUDIO_PIN_2)
#define MOZZI_AUDIO_PIN_2 TIMER1_B_PIN
# endif

# if !defined(MOZZI_PWM_RATE)
#define MOZZI_PWM_RATE 32768
# endif

#define MOZZI_AUDIO_BITS 8
#define MOZZI_AUDIO_BITS_OPTIMISTIC 9
#define MOZZI_AUDIO_BIAS ((uint8_t) 244)
#endif

// Pins for 2 pin HIFI PWM output
#if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_2PIN_PWM)
# if !defined(MOZZI_AUDIO_PIN_1)
#define MOZZI_AUDIO_PIN_1 TIMER1_A_PIN
# endif
# if !defined(MOZZI_AUDIO_PIN_1)
#define MOZZI_AUDIO_PIN_1_LOW TIMER1_B_PIN
# endif

# if !defined(MOZZI_PWM_RATE)
#define MOZZI_PWM_RATE 125000
# endif

# if !defined(MOZZI_PWM_RATE)
#define MOZZI_AUDIO_BITS_PER_CHANNEL 7
# endif

#define MOZZI_AUDIO_BITS (2*MOZZI_AUDIO_BITS_PER_CHANNEL)
#endif

// Step 2: Check
// NOTE: This step is not technically required, but a good idea in any port

// TODO much more
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM, MOZZI_OUTPUT_EXTERNAL_TIMED, MOZZI_OUTPUT_EXTERNAL_CUSTOM)

#if (MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM)
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_CHANNELS, MOZZI_MONO, MOZZI_STEREO)
#endif
#if (MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_2PIN_PWM)
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_CHANNELS, MOZZI_MONO)
#endif

/** should we enforce the following?
#if (MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM) || MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_2PIN_PWM))
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_RATE, 16384, 32768)
#endif */

MOZZI_CHECK_SUPPORTED(MOZZI_ANALOG_READ, MOZZI_ANALOG_READ_NONE, MOZZI_ANALOG_READ_STANDARD)
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_INPUT, MOZZI_AUDIO_INPUT_NONE, MOZZI_AUDIO_INPUT_STANDARD)
#if defined(TIMER1_C_PIN)
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_PIN_1, TIMER1_A_PIN, TIMER1_B_PIN, TIMER1_C_PIN);
#else
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_PIN_1, TIMER1_A_PIN, TIMER1_B_PIN);
#endif

0 comments on commit 80c4908

Please sign in to comment.