NTS-1 companion (wow early sucky version)

NTS-1 companion

A norns library for interfacing with Korg NTS-1.


Photo 1. Kastle 1.5 goes through Torii on norns for gating and then into NTS-1 for effects, while I’m livecoding an arpeggiator on NTS-1.

This is a little library for interfacing with the Korg NTS-1 synth/effect. The script has no user interface, and in it’s current phase it serves mostly for the purposes of livecoding on norns, from Maiden REPL. What might it become in the future? Who knows! In some magic future maybe the custom oscillators and effect will be recognized too, and automatically reacted to. Or even do what the Korg Librarian does?

The Korg NTS-1 exposes almost all of it’s functionality over MIDI (nice!) and rather than, or in addition to thinking “send cc message 42 with value 37”, I like to think more in the line of “set the filter to two-pole bandpass”. So this little utility library is moving in that direction, and once mature it hopefully covers the entire NTS-1 MIDI “API” with meaningful symbol names.

This really sucks and barely works at this point but I want to get an early work-in-progress version out. Loads of bugs left and right :bug: :mosquito: :beetle: . I don’t really even know how to make a Lua module, but I’m learning. Advice is more than welcome esp. on how to organize Lua module code.

Requirements

  • norns
  • Korg NTS-1

Documentation

This is really meant for use from the Maiden, but would integrate to other things too, once it’s more mature.

So for a bit of live-coding fun, first setup with

Nts1 = require "nts1-companion/nts1"
nts1 = midi.connect(2)

Then latch an arpeggiator or push MIDI sequencer from another norns script and start livecoding e.g.

Nts1.osc.tri()
Nts1.sweep.rate(3)
Nts1.sweep.down(30)
Nts1.arp.down()
Nts1.arp.length(5)
Nts1.reverb.hall()
Nts1.reverb.time(30)

&c.

The design principle is to use the familiar front panel of NTS-1 for naming things, so things are mostly organized under names visible on the panel and on the silly little screen, for instance Nts1.filter.cutf(). You can investigate the names of functions with

tab.print(Nts1)

and then drill down to e.g. the filters with

tab.print(Nts1.filter)

Download

Install should work with

;install https://github.com/xmacex/nts1-companion
30 Likes

i love this idea! i didn’t realize how much functionality was accessible from midi!

one thing i would love to add is make it easy to sequence arps (root notes + chord type). i did this before with carp, a browser nts-1 sequencer. it would be awesome if this was available on the norns…it would open a lot of new options :slight_smile:

i didn’t see note sequencing / arp chord type sequencing yet. if you don’t have plans already, would you like a pr from me to add it?

6 Likes

Carp is so cool!

I have no idea how the arp works actually, i was just assuming that NTS-1 latches a single note and then the arp takes it from there. Arp parameters are exposed already, but i don’t know how to do the latching.

How I’m working is basically turning the NTS-1 MIDI Implementation Chart (v. 1.00) into Lua. I have no idea what some of these features are. “Program Change”, “After Touch”, “System Exclusive”, “Inquiry”, “System Common”, “Aux Messages”… what is “Basic Channel”, except of course the one and only:

PR is absolutely welcome. Sorry the code organization is strange as I’m learning Lua, i hope you can make sense of it. It is arranged by the NTS-1 front panel.

4 Likes

yeah that’s it exactly! you give it a note, and a chord type (major, minor, diminished, augmented, sus) and it arps with it. you can also set the arp length too. your code looks wonderful to me actually, and is totally understandable. i’ll get you a pr but i’m sometimes slow so don’t hesitate to beat me to the punch :wink:

2 Likes

You can do the standard nts1:note_on() with just vanilla MIDI and that will sustain until eternity or note1:note_off() whichever comes first, but I don’t know how to start the arp and about those chords. I’ve seen them on carp, but… :woman_shrugging:

Some of the features are not available on the NTS-1 front panel, for instance I’m not sure if you can set the intervals. Are these arp chords such a feature? I always just press down arp until the silly screen says “Latch”, and they press a key and off it goes.

This one I have implemented as Nts1.arp.length(l) expecting l between 1 and 24. It is also one of my favourite features to mess around with, and have a norns metronome change it every once in a while for instance as an “arp of arps”. The MIDI implementation chart also gives intervals for arp which I’ve implemented as Nts1.arp.intervals() but don’t really know what it is. Seems like the arp extends further up into the keyboard, maybe across octaves, but I cannot tell which keys it hits.

:blush: well thank you. Let me know if there is something.

No worries at all and don’t be obliged. There are only good vibes here :surfing_man:

This is the mental image in my mind when thinking about arpeggiation


Shirow: Ghost in the Shell (1995)

The sonic image is in the Berlin school and Philip Glass.

11 Likes

hi! quick question-
do you think it would be possible to get this to interface with the minilogue xd? i remember reading somewhere about the similarities between the nts-1 and minilogue xd, so it was just a thought i had. i believe the example used in the document i read was that you can use effects developed for the nts-1 and minilogue xd interchangeably.

1 Like

it is the channel on which the instrument listens for mode messages (like Omni/Poly.)

[About MIDI-Part 3:MIDI Messages -  ]

the mapping of CC numbers to effect parameters is quite different for the two instruments.

minilogue, last page here
https://cdn.korg.com/us/support/download/files/1362ee55daa0ec780da684b9ad9ad99b.pdf

nts-1, here
https://cdn.korg.com/us/support/download/files/8b4225f3349d609272fcf7ac868212cc.pdf

4 Likes

Thanks, i have a lot to learn about the scope of MIDI and the various ways it can be implemented.

1 Like

Messing around with this. Just to share an example, I have OP-Z and NTS-1 connected to norns, with the following “MIDI through” setup livecoded in norns REPL. All this independently while another norns program (at the time of writing I’m running Benjolis) does it’s thing.

First loading the library with

Nts1 = require "nts1-companion/nts1"

The above also smells where the NTS-1, and binds it to global variable nts1. Then connect OP-Z, which in this case is my MIDI device 2.

opz = midi.connect(2)

Then setting up the channel module track (number 14) of OP-Z to send notes to NTS-1, plus also assign the white knobs, the first four, to NTS-1 oscillator type, oscillator shape, filter frequency and filter resonance:

opz.event = function(data)   local msg = midi.to_msg(data);   if msg.ch == 14 then      if msg.type ~= "clock" then         tab.print(msg);         if msg.type == "note_on" then            nts1:note_on(msg.note)         elseif msg.type == "note_off" then            nts1:note_off(msg.note)         elseif msg.type == "cc" then            if msg.cc == 1 then               Nts1.osc.set_type(msg.val)            elseif msg.cc == 2 then               Nts1.osc.shape(msg.val)            elseif msg.cc == 3 then               Nts1.filter.cutf(msg.val)            elseif msg.cc == 4 then               Nts1.filter.reso(msg.val)            end         end      end   end end
the above code prettified for readability
opz.event = function(data)
   local msg = midi.to_msg(data);
   if msg.ch == 14 then
      if msg.type ~= "clock" then
         tab.print(msg);
         if msg.type == "note_on" then
            nts1:note_on(msg.note)
         elseif msg.type == "note_off" then
            nts1:note_off(msg.note)
         elseif msg.type == "cc" then
            if msg.cc == 1 then
               Nts1.osc.set_type(msg.val)
            elseif msg.cc == 2 then
               Nts1.osc.shape(msg.val)
            elseif msg.cc == 3 then
               Nts1.filter.cutf(msg.val)
            elseif msg.cc == 4 then
               Nts1.filter.reso(msg.val)
            end
         end
      end
   end
end

OP-Z track 14 is now a powerful sequencer for NTS-1, in parallel and independently of what’s going on in norns. Preferably with NTS-1 in arp mode for maximum Berlin school vibes (alternatively Kastle pushing strange clock signal to NTS-1 arpeggiator to queer it up)

:musical_keyboard: → note
:white_circle: :green_circle: → oscillator type
:white_circle: :large_blue_circle: → oscillator shape
:white_circle: :yellow_circle: → filter resonance
:white_circle: :red_circle: → filter resonance

Note that a setup like this can also sequence NTS-1 filter, envelop, or effects from norns in all kinds of (Turing complete) ways. Want to connect the NTS-1 reverb time to the likes on your Instagram feed? Sure!

The way I’m working with longer pieces of code like this, which is smart to slice to smaller functions, is that I program in Emacs with syntax highlighting and all the nice things, then copy-paste to Maiden REPL replacing newlines with a space in either Emacs of JavaScript in the browser. Working on a proof-of-concept, and thought someone might enjoy this kind of a thing.

2 Likes

This might very well be the trashiest sysex protocol implementation you’ve seen in your life, and also pretty dodgy use of a global variable, but it can now f.ex. receive information about installed custom oscillators, mods, delays and reverbs.

Nts1.get_program_info(1, Nts1.CUSTOM.OSC, 1)
My current custom oscillator 1, I think Waves
tab.print(Nts1.get_program_info(1, Nts1.CUSTOM.OSC, 1))
1	240
2	66
3	48
4	0
5	1
6	87
7	73
8	4
9	0
10	0
11	0
12	4
13	2
14	0
15	0
16	1
17	0
18	0
19	0
20	0
21	0
22	0
23	0
24	0
25	0
26	0
27	0
28	0
29	0
30	1
31	0
32	119
33	97
34	118
35	0
36	101
37	115
38	0
39	0
40	0
41	0
42	0
43	0
44	0
45	0
46	0
47	0
48	6
49	0
50	0
51	0
52	247
<ok>
My current custom oscillator 2, I think Souper2
tab.print(Nts1.get_program_info(1, Nts1.CUSTOM.OSC, 2))
1	240
2	66
3	48
4	0
5	1
6	87
7	73
8	4
9	1
10	0
11	0
12	4
13	1
14	0
15	0
16	1
17	0
18	0
19	0
20	0
21	0
22	0
23	0
24	0
25	0
26	0
27	0
28	0
29	1
30	2
31	0
32	83
33	111
34	117
35	0
36	112
37	32
38	50
39	0
40	0
41	0
42	0
43	0
44	0
45	0
46	0
47	0
48	6
49	0
50	0
51	0
52	247
<ok>

In some fantasy future I’ll have interpretations of that nonsense :stuck_out_tongue_closed_eyes: In another fantasy future it will also install custom oscs, mods, delays and reverbs… and maybe replace the Korg Librarian and be able to manage NTS-1 directly from norns without a “real” computer.

Shoutout goes to oscillatorsink whose notes I rely on.

3 Likes