1 # A primitive drum machine interface for Novation Nocturn.
4 # - make sure that Novation Nocturn is connected *and* that the USB device
5 # that corresponds to it can be opened by the current user
6 # - create an ini file containing a scene with a single instrument using
7 # a sampler or fluidsynth engine + some drum mappings in SFZ or SF2
8 # - ensure that the ini file contains 7 drum patterns, pat1..pat7, these
9 # can be copied from cboxrc-example
10 # - user buttons 1..7 start drum patterns
11 # - user button 8 stops the playback
12 # - encoder knob 1 adjusts the volume
13 # - mixer button exits the application
18 sys
.path
= ["./py"] + sys
.path
25 instr_name
= cbox
.Document
.get_scene().status().instruments
.keys()[0]
27 def clamp(val
, min, max):
36 self
.nocturn
= nocturn
.Nocturn()
37 self
.cur_pattern
= None
39 self
.handlers
[83] = self
.on_xfade_touch
41 self
.handlers
[112 + i
] = lambda cmd
, val
: self
.on_buttonN_press(cmd
- 112) if val
> 0 else None
42 self
.handlers
[112 + 7] = lambda cmd
, val
: self
.on_button8_press() if val
> 0 else None
43 self
.handlers
[64] = self
.on_knob1_change
44 self
.handlers
[65] = self
.on_knob2_change
45 self
.handlers
[127] = lambda cmd
, val
: self
.on_mixer_press() if val
> 0 else None
47 def on_knob1_change(self
, cmd
, val
):
48 scene
= cbox
.Document
.get_scene()
49 instr
= scene
.status().instruments
[instr_name
][1]
50 gain
= instr
.get_things('/output/1/status', ['gain']).gain
53 instr
.cmd('/output/1/gain', None, gain
+ val
* 0.5)
55 def on_knob2_change(self
, cmd
, val
):
56 tempo
= cbox
.GetThings("/master/status", ['tempo'], []).tempo
59 tempo
= clamp(tempo
+ val
* 0.5, 30, 300)
60 cbox
.do_cmd('/master/set_tempo', None, [tempo
])
62 def on_buttonN_press(self
, button
):
63 cbox
.do_cmd("/master/stop", None, [])
64 song
= cbox
.Document
.get_song()
65 song
.loop_single_pattern(lambda: song
.load_drum_pattern('pat%d' % (button
+ 1)))
66 cbox
.do_cmd("/master/seek_ppqn", None, [0])
67 cbox
.do_cmd("/master/play", None, [])
68 self
.cur_pattern
= button
70 def on_button8_press(self
):
71 self
.cur_pattern
= None
72 cbox
.do_cmd("/master/stop", None, [])
74 def on_mixer_press(self
):
78 def on_xfade_touch(self
, cmd
, val
):
82 def handler(self
, cmd
, val
):
83 if cmd
in self
.handlers
:
84 self
.handlers
[cmd
](cmd
, val
)
88 self
.nocturn
.poll(self
.handler
)
91 scene
= cbox
.Document
.get_scene()
92 cmds
= nocturn
.NocturnCommands()
93 master
= cbox
.GetThings("/master/status", ['playing'], [])
95 cmds
.setModeButtonLight(i
, self
.cur_pattern
== i
)
96 gain
= scene
.status().instruments
[instr_name
][1].get_things('/output/1/status', ['gain']).gain
97 cmds
.setEncoderMode(0, 0)
98 cmds
.setEncoderValue(0, clamp(int(gain
* 2 + 64), 0, 127))
100 cmds
.setModeButtonLight(7, self
.cur_pattern
is None)
101 self
.nocturn
.execute(cmds
)