-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d8f1a5a
commit 8f49963
Showing
4 changed files
with
178 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#include "kyma.hpp" | ||
|
||
#include <grit/audio/music/note.hpp> | ||
#include <grit/math/remap.hpp> | ||
#include <grit/unit/decibel.hpp> | ||
|
||
namespace grit { | ||
|
||
auto Kyma::prepare(float sampleRate, etl::size_t blockSize) -> void | ||
{ | ||
_sampleRate = sampleRate; | ||
oscillator.setSampleRate(sampleRate); | ||
subOscillator.setSampleRate(sampleRate); | ||
|
||
auto const blockRate = sampleRate / static_cast<float>(blockSize); | ||
_pitchKnob.setSampleRate(blockRate); | ||
_morphKnob.setSampleRate(blockRate); | ||
_attackKnob.setSampleRate(blockRate); | ||
_releaseKnob.setSampleRate(blockRate); | ||
_vOctCV.setSampleRate(blockRate); | ||
_morphCV.setSampleRate(blockRate); | ||
_subGainCV.setSampleRate(blockRate); | ||
_subMorphCV.setSampleRate(blockRate); | ||
} | ||
|
||
auto Kyma::process(StereoBlock<float> const& buffer, ControlInput const& inputs) -> float | ||
{ | ||
auto const pitchKnob = _pitchKnob(inputs.pitchKnob); | ||
auto const attackKnob = _morphKnob(inputs.morphKnob); | ||
auto const morphKnob = _attackKnob(inputs.attackKnob); | ||
auto const releaseKnob = _releaseKnob(inputs.releaseKnob); | ||
|
||
auto const vOctCv = _vOctCV(inputs.vOctCV); | ||
auto const morphCv = _morphCV(inputs.morphCV); | ||
auto const subGainCv = _subGainCV(inputs.subGainCV); | ||
auto const subMorphCv = _subMorphCV(inputs.subMorphCV); | ||
|
||
auto const pitch = grit::remap(pitchKnob, 36.0F, 96.0F); | ||
auto const voltsPerOctave = grit::remap(vOctCv, 0.0F, 60.0F); | ||
auto const note = etl::clamp(pitch + voltsPerOctave, 0.0F, 127.0F); | ||
auto const morph = etl::clamp(morphKnob + morphCv, 0.0F, 1.0F); | ||
|
||
auto const subOffset = inputs.subShift ? 12.0F : 24.0F; | ||
auto const subNoteNumber = etl::clamp(note - subOffset, 0.0F, 127.0F); | ||
auto const subMorph = etl::clamp(subMorphCv, 0.0F, 1.0F); | ||
auto const subGain = grit::remap(subGainCv, 0.0F, 1.0F); | ||
|
||
auto const attack = grit::remap(attackKnob, 0.0F, 0.750F); | ||
auto const release = grit::remap(releaseKnob, 0.0F, 2.5F); | ||
|
||
// oscillator.setWavetable(SineWavetable); | ||
// subOscillator.setWavetable(SineWavetable); | ||
// oscillator.setShapeMorph(morph); | ||
// subOscillator.setShapeMorph(subMorph); | ||
etl::ignore_unused(subMorph, morph); | ||
|
||
oscillator.setFrequency(grit::noteToHertz(note)); | ||
subOscillator.setFrequency(grit::noteToHertz(subNoteNumber)); | ||
|
||
adsr.setAttack(attack * _sampleRate); | ||
adsr.setRelease(release * _sampleRate); | ||
adsr.gate(inputs.gate); | ||
|
||
auto env = 0.0F; | ||
|
||
for (size_t i = 0; i < buffer.extent(1); ++i) { | ||
auto const fmModulator = buffer(0, i); | ||
auto const fmAmount = buffer(1, i); | ||
oscillator.addPhaseOffset(fmModulator * fmAmount); | ||
env = adsr(); | ||
|
||
auto const osc = oscillator() * env; | ||
auto const sub = subOscillator() * env * subGain; | ||
|
||
buffer(0, i) = sub * 0.75F; | ||
buffer(1, i) = osc * 0.75F; | ||
} | ||
|
||
return env; | ||
} | ||
|
||
} // namespace grit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#pragma once | ||
|
||
#include <grit/audio/envelope/envelope_adsr.hpp> | ||
#include <grit/audio/filter/dynamic_smoothing.hpp> | ||
#include <grit/audio/oscillator/variable_shape_oscillator.hpp> | ||
#include <grit/audio/oscillator/wavetable_oscillator.hpp> | ||
#include <grit/audio/stereo/stereo_block.hpp> | ||
|
||
namespace grit { | ||
|
||
struct Kyma | ||
{ | ||
struct ControlInput | ||
{ | ||
float pitchKnob{0}; | ||
float morphKnob{0}; | ||
float attackKnob{0}; | ||
float releaseKnob{0}; | ||
|
||
float vOctCV{0}; | ||
float morphCV{0}; | ||
float subGainCV{0}; | ||
float subMorphCV{0}; | ||
|
||
bool gate{false}; | ||
bool subShift{false}; | ||
}; | ||
|
||
Kyma() = default; | ||
|
||
auto prepare(float sampleRate, etl::size_t blockSize) -> void; | ||
auto process(StereoBlock<float> const& buffer, ControlInput const& inputs) -> float; | ||
|
||
private: | ||
static constexpr auto sine = makeSineWavetable<float, 2048>(); | ||
static constexpr auto wavetable = etl::mdspan{sine.data(), etl::extents<etl::size_t, sine.size()>{}}; | ||
|
||
float _sampleRate{}; | ||
|
||
DynamicSmoothing<float> _pitchKnob{}; | ||
DynamicSmoothing<float> _morphKnob{}; | ||
DynamicSmoothing<float> _attackKnob{}; | ||
DynamicSmoothing<float> _releaseKnob{}; | ||
DynamicSmoothing<float> _vOctCV{}; | ||
DynamicSmoothing<float> _morphCV{}; | ||
DynamicSmoothing<float> _subGainCV{}; | ||
DynamicSmoothing<float> _subMorphCV{}; | ||
|
||
EnvelopeADSR adsr{}; | ||
WavetableOscillator<float, sine.size()> oscillator{wavetable}; | ||
WavetableOscillator<float, sine.size()> subOscillator{wavetable}; | ||
}; | ||
|
||
} // namespace grit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,115 +1,60 @@ | ||
#include <grit/audio/delay/static_delay_line.hpp> | ||
#include <grit/audio/envelope/envelope_adsr.hpp> | ||
#include <grit/audio/filter/dynamic_smoothing.hpp> | ||
#include <grit/audio/music/note.hpp> | ||
#include <grit/audio/oscillator/variable_shape_oscillator.hpp> | ||
#include <grit/audio/oscillator/wavetable_oscillator.hpp> | ||
#include <grit/math/remap.hpp> | ||
#include <grit/unit/decibel.hpp> | ||
#include <grit/eurorack/kyma.hpp> | ||
|
||
#include <daisy_patch_sm.h> | ||
|
||
namespace kyma { | ||
static constexpr auto blockSize = 16U; | ||
static constexpr auto sampleRate = 96'000.0F; | ||
static constexpr auto wavetableSine = grit::makeSineWavetable<float, 2048>(); | ||
static constexpr auto sineWavetable = etl::mdspan{ | ||
wavetableSine.data(), | ||
etl::extents<etl::size_t, wavetableSine.size()>{}, | ||
}; | ||
|
||
auto subOctaveToggle = daisy::Switch{}; | ||
auto envTriggerButton = daisy::Switch{}; | ||
auto patch = daisy::patch_sm::DaisyPatchSM{}; | ||
auto& envelopeGate = patch.gate_in_1; | ||
static constexpr auto blockSize = 16U; | ||
static constexpr auto sampleRate = 96'000.0F; | ||
|
||
auto adsr = grit::EnvelopeADSR{}; | ||
auto oscillator = grit::WavetableOscillator<float, wavetableSine.size()>{sineWavetable}; | ||
auto subOscillator = grit::WavetableOscillator<float, wavetableSine.size()>{sineWavetable}; | ||
auto patch = daisy::patch_sm::DaisyPatchSM{}; | ||
auto toggle = daisy::Switch{}; | ||
auto button = daisy::Switch{}; | ||
auto processor = grit::Kyma{}; | ||
|
||
// auto smoothE = grit::DynamicSmoothing<float, grit::DynamicSmoothingType::Efficient>{}; | ||
// auto smoothA = grit::DynamicSmoothing<float, grit::DynamicSmoothingType::Accurate>{}; | ||
// auto delayN = grit::StaticDelayLine<float, 32, grit::BufferInterpolation::None>{}; | ||
// auto delayL = grit::StaticDelayLine<float, 32, grit::BufferInterpolation::Linear>{}; | ||
// auto delayH = grit::StaticDelayLine<float, 32, grit::BufferInterpolation::Hermite>{}; | ||
|
||
auto audioCallback(daisy::AudioHandle::InputBuffer in, daisy::AudioHandle::OutputBuffer out, size_t size) -> void | ||
auto audioCallback( | ||
daisy::AudioHandle::InterleavingInputBuffer in, | ||
daisy::AudioHandle::InterleavingOutputBuffer out, | ||
size_t size | ||
) -> void | ||
{ | ||
patch.ProcessAllControls(); | ||
|
||
auto const pitchKnob = patch.GetAdcValue(daisy::patch_sm::CV_1); | ||
auto const attackKnob = patch.GetAdcValue(daisy::patch_sm::CV_2); | ||
auto const morphKnob = patch.GetAdcValue(daisy::patch_sm::CV_3); | ||
auto const releaseKnob = patch.GetAdcValue(daisy::patch_sm::CV_4); | ||
|
||
auto const vOctCv = patch.GetAdcValue(daisy::patch_sm::CV_5); | ||
auto const morphCv = patch.GetAdcValue(daisy::patch_sm::CV_6); | ||
auto const subGainCv = patch.GetAdcValue(daisy::patch_sm::CV_7); | ||
auto const subMorphCv = patch.GetAdcValue(daisy::patch_sm::CV_8); | ||
|
||
auto const pitch = grit::remap(pitchKnob, 36.0F, 96.0F); | ||
auto const voltsPerOctave = grit::remap(vOctCv, 0.0F, 60.0F); | ||
auto const note = etl::clamp(pitch + voltsPerOctave, 0.0F, 127.0F); | ||
auto const morph = etl::clamp(morphKnob + morphCv, 0.0F, 1.0F); | ||
|
||
auto const subOffset = subOctaveToggle.Pressed() ? 12.0F : 24.0F; | ||
auto const subNoteNumber = etl::clamp(note - subOffset, 0.0F, 127.0F); | ||
auto const subMorph = etl::clamp(subMorphCv, 0.0F, 1.0F); | ||
auto const subGain = grit::remap(subGainCv, 0.0F, 1.0F); | ||
|
||
auto const attack = grit::remap(attackKnob, 0.0F, 0.750F); | ||
auto const release = grit::remap(releaseKnob, 0.0F, 2.5F); | ||
|
||
// oscillator.setWavetable(SineWavetable); | ||
// subOscillator.setWavetable(SineWavetable); | ||
// oscillator.setShapeMorph(morph); | ||
// subOscillator.setShapeMorph(subMorph); | ||
etl::ignore_unused(subMorph, morph); | ||
|
||
oscillator.setFrequency(grit::noteToHertz(note)); | ||
subOscillator.setFrequency(grit::noteToHertz(subNoteNumber)); | ||
|
||
adsr.setAttack(attack * sampleRate); | ||
adsr.setRelease(release * sampleRate); | ||
adsr.gate(envelopeGate.State() or envTriggerButton.Pressed()); | ||
|
||
for (size_t i = 0; i < size; ++i) { | ||
auto const fmModulator = IN_L[i]; | ||
auto const fmAmount = IN_R[i]; | ||
oscillator.addPhaseOffset(fmModulator * fmAmount); | ||
|
||
auto const env = adsr(); | ||
patch.WriteCvOut(daisy::patch_sm::CV_OUT_1, env * 5.0F); | ||
patch.WriteCvOut(daisy::patch_sm::CV_OUT_2, env * 5.0F); | ||
|
||
auto const osc = oscillator() * env; | ||
auto const sub = subOscillator() * env * subGain; | ||
|
||
OUT_L[i] = sub * 0.75F; | ||
OUT_R[i] = osc * 0.75F; | ||
} | ||
toggle.Debounce(); | ||
button.Debounce(); | ||
patch.SetLed(not toggle.Pressed()); | ||
|
||
auto const controls = grit::Kyma::ControlInput{ | ||
.pitchKnob = patch.GetAdcValue(daisy::patch_sm::CV_1), | ||
.morphKnob = patch.GetAdcValue(daisy::patch_sm::CV_3), | ||
.attackKnob = patch.GetAdcValue(daisy::patch_sm::CV_2), | ||
.releaseKnob = patch.GetAdcValue(daisy::patch_sm::CV_4), | ||
.vOctCV = patch.GetAdcValue(daisy::patch_sm::CV_5), | ||
.morphCV = patch.GetAdcValue(daisy::patch_sm::CV_6), | ||
.subGainCV = patch.GetAdcValue(daisy::patch_sm::CV_7), | ||
.subMorphCV = patch.GetAdcValue(daisy::patch_sm::CV_8), | ||
.gate = patch.gate_in_1.State() or button.Pressed(), | ||
.subShift = toggle.Pressed(), | ||
}; | ||
|
||
auto const block = grit::StereoBlock<float>{out, size}; | ||
auto const env = processor.process(block, controls); | ||
patch.WriteCvOut(daisy::patch_sm::CV_OUT_2, env * 5.0F); | ||
} | ||
|
||
} // namespace kyma | ||
|
||
auto main() -> int | ||
{ | ||
using namespace kyma; | ||
kyma::patch.Init(); | ||
|
||
patch.Init(); | ||
patch.SetAudioSampleRate(sampleRate); | ||
patch.SetAudioBlockSize(blockSize); | ||
patch.StartAudio(audioCallback); | ||
kyma::toggle.Init(daisy::patch_sm::DaisyPatchSM::B8); | ||
kyma::button.Init(daisy::patch_sm::DaisyPatchSM::B7); | ||
|
||
subOctaveToggle.Init(daisy::patch_sm::DaisyPatchSM::B8); | ||
envTriggerButton.Init(daisy::patch_sm::DaisyPatchSM::B7); | ||
kyma::processor.prepare(kyma::sampleRate, kyma::blockSize); | ||
|
||
oscillator.setSampleRate(sampleRate); | ||
subOscillator.setSampleRate(sampleRate); | ||
kyma::patch.SetAudioSampleRate(kyma::sampleRate); | ||
kyma::patch.SetAudioBlockSize(kyma::blockSize); | ||
kyma::patch.StartAudio(kyma::audioCallback); | ||
|
||
while (true) { | ||
subOctaveToggle.Debounce(); | ||
envTriggerButton.Debounce(); | ||
patch.SetLed(not subOctaveToggle.Pressed()); | ||
} | ||
while (true) {} | ||
} |