1
0
mirror of https://github.com/sjlongland/atinysynth.git synced 2025-09-13 18:13:16 +10:00
atinysynth/synth.h
Stuart Longland d1cbf66261
waveform: Add support for frequency scaling.
For conniseurs of DDS frequency generation, we provide the option of
scaling the integer frequency so that frequency may be specified to
fractions of 1Hz.  This is useful in musical applications where the
frequency of most notes is a non-integer value.
2017-07-25 07:59:23 +10:00

122 lines
3.4 KiB
C

/*!
* Polyphonic synthesizer for microcontrollers.
* (C) 2017 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
*/
#ifndef _SYNTH_H
#define _SYNTH_H
#include "voice.h"
#include "debug.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 SYNTH_CFG
#include SYNTH_CFG
#endif
#ifndef SYNTH_FREQ
/*!
* Sample rate for the synthesizer: this needs to be declared in the
* application.
*/
extern const uint16_t __attribute__((weak)) synth_freq;
#else
#define synth_freq SYNTH_FREQ
#endif
#ifdef SYNTH_FREQ_SCALE
/*!
* Amount of scaling to apply to synthesizer output frequencies. This
* right-shifts frequencies, allowing for some bits to be used to indicate
* fractional components, trading off frequency range for precision.
*
* Precision is 1/(2^SYNTH_FREQ_SCALE) Hz.
* Range is 0-((65536/(2^SYNTH_FREQ_SCALE))-1).
*
* The default of 0 applies no scaling, allowing (integer) frequencies between
* 0 and 65.535 kHz. The value 1 multiplies everything by two, allowing
* frequencies between 0 and 32.767kHz with 500mHz precision.
*/
#define SYNTH_FREQ_SCALE (0)
#endif
/*!
* Polyphonic synthesizer structure
*/
struct poly_synth_t {
/*! Pointer to voices. There may be up to 16 voices referenced. */
struct voice_ch_t* voice;
/*!
* Bit-field enabling given voices. This allows selective turning
* on and off of given voice channels. If the corresponding bit is
* not a 1, then that channel is not computed.
*
* Note no bounds checking is done, if you have only defined 4
* channels, then only set bits 0-3, don't set bits 4 onwards here.
*/
volatile uintptr_t enable;
/*!
* Bit-field muting given voices. This allows for selective adding
* of voices to the overall output. If a field is 1, then that voice
* channel is not included. (Note, disabled channels are *also*
* not included.)
*/
volatile uintptr_t mute;
};
/*!
* Compute the next synthesizer sample.
*/
static inline int8_t poly_synth_next(struct poly_synth_t* const synth) {
int16_t sample = 0;
uintptr_t mask = 1;
uint8_t idx = 0;
while (mask) {
if (synth->enable & mask) {
/* Channel is enabled */
int8_t ch_sample = voice_ch_next(
&(synth->voice[idx]));
_DPRINTF("poly %p ch=%d out=%d\n",
synth, idx, ch_sample);
if (!(synth->mute & mask))
sample += ch_sample;
if (voice_ch_is_done(&synth->voice[idx])) {
_DPRINTF("poly %p ch=%d done\n", synth, idx);
synth->enable &= ~mask;
adsr_reset(&synth->voice[idx].adsr);
}
}
idx++;
mask <<= 1;
}
/* Handle clipping */
if (sample > INT8_MAX)
sample = INT8_MAX;
else if (sample < INT8_MIN)
sample = INT8_MIN;
return sample;
};
#endif
/*
* vim: set sw=8 ts=8 noet si tw=72
*/