1
0
mirror of https://github.com/sjlongland/polyphonic-synthesizer.git synced 2025-09-13 08:42:22 +10:00
polyphonic-synthesizer/poly.h

253 lines
7.1 KiB
C

#ifndef _POLY_H
#define _POLY_H
/*!
* Polyphonic synthesizer for microcontrollers.
* (C) 2016 Stuart Longland
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <stdint.h>
#include <errno.h>
/*
* _POLY_CFG_H is a definition that can be given when compiling poly.c
* and firmware code to define a header file that contains definitions for
* the Polyphonic synthesizer.
*/
#ifdef _POLY_CFG
#include _POLY_CFG
#endif
/*!
* Polyphonic event. This is a base struct for describing what happens
* within a voice channel. An array of these forms a musical piece or
* sound effect. Each event can take the form of a chnage to a voice's
* parameters, or timing events.
*/
struct poly_evt_t {
uint16_t flags; /*!< Event flags */
uint16_t value; /*!< New register value */
};
/* Event flags */
/*!
* Bits 15-12 represent the event type.
*/
#define POLY_EVT_TYPE_BIT (12)
/*!
* Bit mask for event type.
*/
#define POLY_EVT_TYPE_MASK (0x0f << POLY_EVT_TYPE_BIT)
/*!
* END event. This terminates the musical piece and causes a reset of
* the synthesizer state. Event is valid at any time.
*/
#define POLY_EVT_TYPE_END (0x00 << POLY_EVT_TYPE_BIT)
/*!
* TIME event. This indicates the synthesizer should emit samples with the
* currently defined parameters for the number of samples given in the
* value field. Event is valid at any time.
*/
#define POLY_EVT_TYPE_TIME (0x01 << POLY_EVT_TYPE_BIT)
/*!
* ENABLE event. This turns on and off computation of the named channels.
*/
#define POLY_EVT_TYPE_ENABLE (0x02 << POLY_EVT_TYPE_BIT)
/*!
* MUTE event. This turns on and off inclusion of a channel in the output.
*/
#define POLY_EVT_TYPE_MUTE (0x03 << POLY_EVT_TYPE_BIT)
/*!
* IFREQ change event. This indicates the immediate frequency for a voice
* channel is to change to the value given in Hz, or, if the frequency is
* zero, the channel is to emit a DC or linearly varying signal.
*
* Channel number is given in bits 12-8 of the flags register.
*/
#define POLY_EVT_TYPE_IFREQ (0x04 << POLY_EVT_TYPE_BIT)
/*!
* DFREQ change event. This indicates the frequency step is to change to
* the given value in Hz. The frequency of the channel will step by this
* amount every N samples, where N is set by DSCALE.
*
* Channel number is given in bits 12-8 of the flags register.
*/
#define POLY_EVT_TYPE_DFREQ (0x05 << POLY_EVT_TYPE_BIT)
/*!
* PMOD change event. Change phase modulation configuration.
*
* If value is UINT16_MAX: Disable phase modulation
* Otherwise, modulate the phase using the channel number given.
*
* Channel number is given in bits 12-8 of the flags register.
*/
#define POLY_EVT_TYPE_PMOD (0x06 << POLY_EVT_TYPE_BIT)
/*!
* IAMP change event. This indicates the immediate amplitude of the
* channel is to be set to the value given.
*
* Channel number is given in bits 12-8 of the flags register.
*/
#define POLY_EVT_TYPE_IAMP (0x08 << POLY_EVT_TYPE_BIT)
/*!
* DAMP change event. This indicates the amplitude step is to change to
* the given value. The amplitude will change by this amount every N
* samples, where N is set by DSCALE.
*
* Channel number is given in bits 12-8 of the flags register.
*/
#define POLY_EVT_TYPE_DAMP (0x09 << POLY_EVT_TYPE_BIT)
/*!
* AMOD change event. Change amplitude modulation configuration.
*
* If value is UINT16_MAX: Disable amplitude modulation
* Otherwise, modulate the amplitude using the channel number given.
*
* Channel number is given in bits 12-8 of the flags register.
*/
#define POLY_EVT_TYPE_AMOD (0x0a << POLY_EVT_TYPE_BIT)
/*!
* ASCALE change event. Amplitudes are to be left-shifted by this number
* of bits after multiplication with a sample.
*
* Channel number is given in bits 12-8 of the flags register.
*/
#define POLY_EVT_TYPE_ASCALE (0x0b << POLY_EVT_TYPE_BIT)
/*!
* DSCALE change event. Every N samples (given here), the amplitude and
* frequency of the channel will be adjusted.
*
* Channel number is given in bits 12-8 of the flags register.
*/
#define POLY_EVT_TYPE_DSCALE (0x0f << POLY_EVT_TYPE_BIT)
/*!
* Position of channel number field.
*/
#define POLY_CH_BIT (8)
/*!
* Mask for channel number field.
*/
#define POLY_CH_MASK (0x0f << POLY_VOICE_CH_BIT)
/*!
* Voice state machine. A "voice" is simply a sinusoidal channel. It
* may be modulated by a static linear function, or by taking the output
* from another channel and summing that.
*
* Each voice has its own sample timing counter which starts at zero and
* counts upwards.
*/
struct poly_voice_t {
int16_t sample; /*!< Sample last computed */
uint16_t time; /*!< Time (samples) for voice */
uint16_t freq; /*!< Current frequency */
int16_t dfreq; /*!< Delta frequency */
uint16_t dscale; /*!< Delta time scale */
uint8_t amp; /*!< Current amplitude */
int8_t damp; /*!< Delta amplitude */
uint8_t ascale; /*!< Amplitude scale */
uint8_t pmod; /*!< Phase modulation channel */
uint8_t amod; /*!< Amplitude modulation channel */
uint8_t flags; /*!< Flags register */
};
#ifndef _POLY_NUM_CHANNELS
/*!
* Number of voice channels: this needs to be declared in the application.
* Overridden by defining _POLY_NUM_CHANNELS.
*/
extern const uint8_t __attribute__((weak)) poly_num_channels;
#else
#define poly_num_channels _POLY_NUM_CHANNELS
#endif
#ifndef _POLY_FREQ
/*!
* Sample rate for the synthesizer: this needs to be declared in the
* application.
*/
extern const uint16_t __attribute__((weak)) poly_freq;
#else
#define poly_freq _POLY_FREQ
#endif
#ifndef _POLY_FREQ
/*!
* Maximum frequency for the synthesizer: this needs to be declared in the
* application. This should be set at the nyquist frequency.
* (poly_freq/2)
*/
extern const uint16_t __attribute__((weak)) poly_freq_max;
#else
#define poly_freq_max (poly_freq/2)
#endif
#ifndef _POLY_NUM_CHANNELS
/*!
* Voice channel array: this needs to be declared in the application.
*/
extern struct __attribute__((weak)) poly_voice_t poly_voice[];
#endif
/*!
* Number of samples remaining before the next set of events.
*/
extern volatile uint16_t poly_remain;
/*!
* Reset the polyphonic synthesizer.
*/
void poly_reset();
/*!
* Load a sample event into the polyphonic registers.
* @param event Polyphonic event to load.
* @retval 0 Success
* @retval -EINVAL Bad event
* @retval -ERANGE Bad value
* @retval -EINPROGRESS Waiting for timing event
*/
int poly_load(const struct poly_evt_t* event);
/*!
* Retrieve the next output sample from the polyphonic synthesizer.
*/
int16_t poly_next();
/*
* vim: set sw=8 ts=8 noet si tw=72
*/
#endif