migration from 'smp_v1p0' dev. for 'sampler' -> skip irrelavant note msg. and keep playing
210 lines
5.8 KiB
C++
210 lines
5.8 KiB
C++
/* Audio Library for Teensy 3.X
|
|
* Copyright (c) 2016, Byron Jacquot, SparkFun Electronics
|
|
*
|
|
* Development of this audio library was funded by PJRC.COM, LLC by sales of
|
|
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
|
|
* open source software by purchasing Teensy or other PJRC products.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice, development funding notice, and this permission
|
|
* notice shall be included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#include <Arduino.h>
|
|
#include "synth_simple_drum.h"
|
|
|
|
extern "C" {
|
|
extern const int16_t AudioWaveformSine[257];
|
|
}
|
|
|
|
void AudioSynthSimpleDrum::noteOn(void)
|
|
{
|
|
__disable_irq();
|
|
|
|
wav_phasor = 0;
|
|
wav_phasor2 = 0;
|
|
|
|
env_lin_current = 0x7fff0000;
|
|
|
|
__enable_irq();
|
|
}
|
|
|
|
void AudioSynthSimpleDrum::secondMix(float level)
|
|
{
|
|
// As level goes from 0.0 to 1.0,
|
|
// second goes from 0 to 1/2 scale
|
|
// first goes from full scale to half scale.
|
|
|
|
if(level < 0)
|
|
{
|
|
level = 0;
|
|
}
|
|
else if(level > 1.0)
|
|
{
|
|
level = 1.0;
|
|
}
|
|
|
|
__disable_irq();
|
|
wav_amplitude2 = level * 0x3fff;
|
|
wav_amplitude1 = 0x7fff - wav_amplitude2;
|
|
__enable_irq();
|
|
}
|
|
|
|
|
|
void AudioSynthSimpleDrum::pitchMod(float depth)
|
|
{
|
|
int32_t intdepth, calc;
|
|
|
|
// Validate parameter
|
|
if(depth < 0)
|
|
{
|
|
depth = 0;
|
|
}
|
|
else if(depth > 1.0)
|
|
{
|
|
depth = 1.0;
|
|
}
|
|
|
|
// Depth is float, 0.0..1.0
|
|
// turn 0.0 to 1.0 into
|
|
// 0x0 to 0x3fff;
|
|
intdepth = depth * 0x7fff;
|
|
|
|
// Lets turn it into 2.14, in range between -0.75 and 2.9999, woth 0 at 0.5
|
|
// It becomes the scalar for the modulation component of the phasor increment.
|
|
if(intdepth < 0x4000)
|
|
{
|
|
// 0 to 0.5 becomes
|
|
// -0x3000 (0xffffCfff) to 0 ()
|
|
calc = ((0x4000 - intdepth) * 0x3000 )>> 14;
|
|
calc = -calc;
|
|
}
|
|
else
|
|
{
|
|
// 0.5 to 1.0 becomes
|
|
// 0x00 to 0xbfa0
|
|
calc = ((intdepth - 0x4000) * 0xc000)>> 14;
|
|
}
|
|
|
|
// Call result 2.14 format (max of ~3.99...approx 4)
|
|
// See note in update().
|
|
wav_pitch_mod = calc;
|
|
}
|
|
|
|
|
|
|
|
void AudioSynthSimpleDrum::update(void)
|
|
{
|
|
audio_block_t *block_wav;
|
|
int16_t *p_wave, *end;
|
|
int32_t sin_l, sin_r, interp, mod, mod2, delta;
|
|
int32_t interp2;
|
|
int32_t index, scale;
|
|
bool do_second;
|
|
|
|
int32_t env_sqr_current; // the square of the linear value - inexpensive quasi exponential decay.
|
|
|
|
block_wav = allocate();
|
|
if (!block_wav) return;
|
|
p_wave = (block_wav->data);
|
|
end = p_wave + AUDIO_BLOCK_SAMPLES;
|
|
|
|
// 50 is arbitrary threshold...
|
|
// low values of second are inaudible, and we can save CPU cycles
|
|
// by not calculating second when it's really quiet.
|
|
do_second = (wav_amplitude2 > 50);
|
|
|
|
while(p_wave < end)
|
|
{
|
|
// Do envelope first
|
|
if(env_lin_current < 0x0000ffff)
|
|
{
|
|
// If envelope has expired, then stuff zeros into output buffer.
|
|
*p_wave = 0;
|
|
p_wave++;
|
|
}
|
|
else
|
|
{
|
|
env_lin_current -= env_decrement;
|
|
env_sqr_current = multiply_16tx16t(env_lin_current, env_lin_current) ;
|
|
|
|
// do wave second;
|
|
wav_phasor += wav_increment;
|
|
|
|
// modulation changes how we use the increment
|
|
// the increment will be scaled by the modulation amount.
|
|
//
|
|
// Pitch mod is in range [-0.75 .. 3.99999] in 2.14 format
|
|
// Current envelope value gets scaled by mod depth.
|
|
// Then phasor increment gets scaled by that.
|
|
mod = signed_multiply_32x16b((env_sqr_current), (wav_pitch_mod>>1)) >> 13;
|
|
mod2 = signed_multiply_32x16b(wav_increment<<3, mod>>1);
|
|
|
|
wav_phasor += (mod2);
|
|
wav_phasor &= 0x7fffffff;
|
|
|
|
if(do_second)
|
|
{
|
|
// A perfect fifth uses increment of 1.5 times regular increment
|
|
wav_phasor2 += wav_increment;
|
|
wav_phasor2 += (wav_increment >> 1);
|
|
wav_phasor2 += mod2;
|
|
wav_phasor2 += (mod2 >> 1);
|
|
wav_phasor2 &= 0x7fffffff;
|
|
}
|
|
|
|
// Phase to Sine lookup * interp:
|
|
index = wav_phasor >> 23; // take top valid 8 bits
|
|
sin_l = AudioWaveformSine[index];
|
|
sin_r = AudioWaveformSine[index+1];
|
|
|
|
// The fraction of the phasor in time we are between L and R
|
|
// is the same as the fraction of the ampliture of that interval we should add
|
|
// to L.
|
|
delta = sin_r-sin_l;
|
|
scale = (wav_phasor >> 7) & 0xfFFF;
|
|
delta = (delta * scale)>> 16;
|
|
interp = sin_l + delta;
|
|
|
|
if(do_second)
|
|
{
|
|
index = wav_phasor2 >> 23; // take top valid 8 bits
|
|
sin_l = AudioWaveformSine[index];
|
|
sin_r = AudioWaveformSine[index+1];
|
|
|
|
delta = sin_r-sin_l;
|
|
scale = (wav_phasor2 >> 7) & 0xFFFF;
|
|
delta = (delta * scale)>> 16;
|
|
interp2 = sin_l + delta;
|
|
|
|
// Then scale and add the two waves
|
|
interp2 = (interp2 * wav_amplitude2 ) >> 15;
|
|
interp = (interp * wav_amplitude1) >> 15;
|
|
interp = interp + interp2;
|
|
}
|
|
|
|
*p_wave = signed_multiply_32x16b(env_sqr_current, interp ) >> 15 ;
|
|
p_wave++;
|
|
}
|
|
}
|
|
|
|
transmit(block_wav, 0);
|
|
release(block_wav);
|
|
|
|
}
|
|
|