Korg NTS-1
The Korg NTS-1 is a programmable digital monophonic synthesizer ("monosynth") and effects unit.
Custom oscillators and effects can be programmed in C (plus a subset of C++) using Korg's logue SDK.
I find the NTS-1 to be a really fun synth to mess around with, and really the only hardware synth outside of the [[deluge]] that I enjoy using. I think there are a few reasons for that, but a big one is the lack of presets. If I want to make a sound with the NTS-1, I need to engineer that sound more or less from scratch ([[sound-design]]), which leads to fun discoveries that I have to capture in the moment: once the synth is powered off, that patch is gone! This is a big part of the Eurorack ethos, except the NTS-1 costs an order of magnitude less than an equivalent Eurorack setup. The only comparable Eurorack modules I could find were the Electro-Smith Daisy Patch or Patch.Init(), and those cost at least double the price of the NTS-1 (and that's without a case, power supply, and other modules to play with). Also those only allow you to load one patch, although I suppose you could create a patch with a menu to switch between "sub-patches".
Since the NTS-1 is an external synth, I can run it through guitar pedals for more effects than those in its internal effects chain. Running it through a fuzz pedal and/or an amp sim pedal adds some nice warmth to the sound.
Most annoying thing has to be the build quality and connections. It's not poorly built or faulty, it's just a bit too delicate. All the audio/MIDI jacks are 3.5mm mini jacks, and the power connection is Mini-USB. Not the most durable connections. I'd like to build an enclosure that gives it 1/4" audio jacks, 5-pin DIN MIDI, a real power connector, and an internal battery, much like this project from Caspius Labs.
Custom oscillators/FX
Finding info about how to write your own oscillators and effects is tricky. Below is the bare-minimum that I could figure out to implement a basic sine oscillator:
// Based off https://github.com/damnatron/logue-sdk/blob/master/platform/prologue/contrib/sine/sine.cpp
#include "userosc.h"
typedef struct State {
float phase;
} State;
static State s_state;
void OSC_INIT(uint32_t platform, uint32_t api)
{
s_state.phase = 0.f;
}
// Rendering function for each cycle.
// (frequency = number of cycles/second)
void OSC_CYCLE(
const user_osc_param_t * const params, // Current realtime parameter state.
int32_t *yn, // Output buffer.
const uint32_t frames // Size of output buffer. (1 sample per frame)
)
{
// Notes:
// Oscillators are NOT stereo, so the number of frames that need to get pushed to the output buffer
// is equal to the number of samples we need to generate. For Mod FX (which are stereo), each
// frome needs 2 samples (L and R)
// Get pointers to the start and end of the output buffer:
q31_t * __restrict output_buffer_cursor = (q31_t *)yn;
const q31_t * output_buffer_end = output_buffer_cursor + frames;
// For the current note + mod, get the phase offset (w0) using osc_w0f_for_note.
// The phase offset is how much we need to increment the phase every sample.
uint8_t note = (params->pitch) >> 8;
uint8_t mod = (params->pitch) & 0xFF;
const float phase_offset = osc_w0f_for_note(note, mod);
// phase ranges from 0 to 1 (we clamp it on line 48), representing 0 to 2PI
float phase = s_state.phase;
// Generate samples and push them to the output buffer until we reach
// the end of the output buffer:
for (; output_buffer_cursor != output_buffer_end;)
{
const float sample = osc_softclipf(0.05f, osc_sinf(phase));
*(output_buffer_cursor++) = f32_to_q31(sample);
phase += phase_offset;
phase -= (uint32_t)phase; // clamp phase offset to 0-1 (discard whole part)
}
// we need to store the last phase for this cycle of audio so the
// next cycle can start on the same phase
s_state.phase = phase;
}
void OSC_NOTEON(const user_osc_param_t * const params)
{
}
void OSC_NOTEOFF(const user_osc_param_t * const params)
{
}
void OSC_PARAM(uint16_t index, uint16_t value)
{
}
Shortcuts
The NTS-1 has a decent amount of features hidden behind shortcuts (pretty much all accessed by holding down a button and turning the A or B knobs).
Oscillator
The LFO can target 2 parameters: the oscillator pitch (P) or the waveshaping (or shape) amount (S). It cannot target both parameters at once, only one or the other.
While holding OSC... | Function |
---|---|
A knob | LFO frequency |
B knob | LFO target and depth (can target shape (S) or pitch (P)) |
Filter
While holding FILTER... | Function |
---|---|
A knob | Cutoff sweep frequency |
B knob | Cutoff sweep depth (can sweep up and down) |
Envelope Generator
While holding EG... | Function |
---|---|
A knob | Tremolo frequency |
B knob | Tremolo depth |
FX
While holding DELAY or REVERB... | Function |
---|---|
A knob | none |
B knob | Wet/dry balance |
Arpeggiator
Press and hold the ARP button to latch the arpeggiator. Press it again to un-latch it.
Pressing any other buttons while holding the ARP button sets the intervals between notes of the pattern.
While holding ARP... | Function |
---|---|
OSC | Octave |
FILTER | Major triad |
EG | Major suspended |
MOD | Major augmented |
DELAY | Minor triad |
REVERB | Minor diminished |
TYPE knob | Arp pattern (Up, Down, Up-Down, Down-Up, Converge, Diverge, Converge-Diverge, Diverge-Converge, Random, Stochastic (Brownian?)) |
A knob | Pattern length |
B knob | Step duration (if synced externally), tempo (if not synced externally) |
Global Parameters
Hold down the REVERB button while powering on the NTS-1 to access the global parameter editor.
In the global parameter editor, use the TYPE knob to select a parameter and change its value with the B knob.
REVERB cancels parameter changes, while ARP saves parameter changes.
links
- MIDI Implementation
- Eurorack Custom Oscillators
- hammondeggs logue-sdk plugins
- https://github.com/hypercubed-music/nts-1
Backlinks
No backlinks found.