forest-all-around/sampler/lib/Audio_SdFat/synth_simple_drum.cpp
Dooho Yi 91f92c0e6c audio & sd lib upgrade (SdFatSdioEX)
migration from 'smp_v1p0' dev.
for 'sampler' -> skip irrelavant note msg. and keep playing
2019-12-11 23:37:44 +09:00

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);
}