Overview Clamps Packages CM Dictionary Clamps Dictionary Fomus
Next: Other Utility Functions , Previous: MIDI Controllers , Up: MIDI Controllers , Home: General

Clamps Packages

Using a Korg NanoKONTROL2 Controller
  • Preparation

    Restore the NanoKontrol2 to the factory defaults and set the LED Mode in the Common section of the Korg Kontrol Editor application to "External".

  • Initialization

    To initialize the controller, issue the add-midi-controller method with the nanoktl2-midi class and a custom ID and optionally its channel as arguments:

    ;; create an instance of a NanoKONTROL2 midi-controller with ID :nk2
    ;; using MIDI channel 1 and add it to the registry:
    
    (add-midi-controller 'nanoktl2-midi :nk2 :chan 1)
    

    If the NanoKONTROL2 hardware device is connected to the incudine in/output ports, it now can be used. For details about the slots and their layout, refer to nanoktl2-midi in the Clamps Dictionary.

  • Adding Behaviour

    We can add behaviour to the instance by attaching watch functions to the faders and knobs or trigger functions to the buttons:

    • Faders and Knobs
      (with-slots (unwatch nk2-faders) (find-controller :nk2)
        (dotimes (i 8)
          (let ((n i))
            (push (watch
                   (lambda () (msg :warn (format nil "Knob ~a turned: ~a" (1+ n)
                                             (get-val (aref nk2-faders n))))))
                  unwatch)
            (push (watch
                   (lambda () (msg :warn (format nil "Fader ~a moved: ~a" (1+ n)
                                            (get-val (aref nk2-faders (+ n 8)))))))
                  unwatch))))
      ;; => nil
      ;;
      ;; output in the REPL:
      ;; warn: Knob 1 turned: 0
      ;; warn: Fader 1 moved: 0
      ;; warn: Knob 2 turned: 0
      ;; warn: Fader 2 moved: 0
      ;; warn: Knob 3 turned: 0
      ;; warn: Fader 3 moved: 0
      ;; warn: Knob 4 turned: 0
      ;; warn: Fader 4 moved: 0
      ;; warn: Knob 5 turned: 0
      ;; warn: Fader 5 moved: 0
      ;; warn: Knob 6 turned: 0
      ;; warn: Fader 6 moved: 0
      ;; warn: Knob 7 turned: 0
      ;; warn: Fader 7 moved: 0
      ;; warn: Knob 8 turned: 0
      ;; warn: Fader 8 moved: 0
      

      The output in the REPL signals that the watch function has been established for all knobs and faders.

      Moving a fader works like expected:

      clamps> 
      warn: Fader 1 moved: 1.0
      warn: Fader 1 moved: 2.0
      warn: Fader 1 moved: 3.0
      warn: Fader 1 moved: 4.0
      warn: Fader 1 moved: 5.0
      warn: Fader 1 moved: 6.0
      warn: Fader 1 moved: 7.0
      warn: Fader 1 moved: 8.0
      warn: Fader 1 moved: 9.0
      <...>
      clamps> 
      
      Important Note

      In the above Fader/Knob example, it might not be obvious that the binding of n to i using the let in the body of the dotimes is crucial for this to work. If it isn't clear, why it wouldn't work to use i directly in the lambda forms of the watch expressions, refer to the section Excursion: Closures. The section tries to shed some light on binding and the difference of compile-time vs. run-time. Knowing how to deal with closures is a recurring necessity when working with Clamps and a thorough understanding indispensible.

    • Buttons

      A button is inspired by a Gui element of a button, adding click events on the button. It is implemented in cl-refs as a bang-object, a ref-cell with an additional trigger function, which ist invoked on a button press/click.

      To add an action to the button, use the function add-trigger-fn.

      Here is an example:

      (add-trigger-fn (tr-play (find-controller :nk2)) (lambda () (msg :warn "tr-play Button pressed.")))
      ;; => nil
      
      (trigger (tr-play (find-object :nk2)))
      ;; output in the REPL:
      ;; warn: tr-play Button pressed.
      

      This behaviour is automatically implemented in the handle-midi-in method of a nanoktl2-midi instance: When pressing the tr-play button on the NanoKONTROL2 Hardware Controller, it will call the trigger function on the tr-play slot of the instance and you should see the same message in the REPL as before:

      clamps> 
      warn: tr-play Button pressed.
      clamps> 
      

      The same result is achievd by calling trigger with the bang-object as argument:

      Removing the trigger functions from the button can be done using the function remove-all-triggers:

      (remove-all-triggers (tr-play (find-controller :nk2)))
      

      Like watch, add-trigger-fn returns a function to remove the trigger function(s) from the ref-cell. Therefore you can also implement adding the trigger function to the nanoktl2-midi instance like this to be able to have a finer control over selectively adding and removing trigger functions for ref-cells:

      (defvar *unwatch-triggers* nil)
      (push (add-trigger-fn (tr-play (find-controller :nk2)) (lambda () (msg :warn "tr-play Button pressed.")))
            *unwatch-triggers*)
      ;;  => (#<function (lambda () :in add-trigger-fn) {100A94123B}>
      
      ;; remove the trigger function:
      
      (progn
        (map nil #'funcall *unwatch-triggers*)
        (setf *unwatch-triggers* nil))
      ; => nil
      
      ;; abbreviation of the above expression:
      
      (setf *unwatch-triggers*
            (map nil #'funcall *unwatch-triggers*))
      ; => nil
      
      Note

      As buttons are extended ref-cells, they also have a value slot which can be accessed and manipulated like any normal ref-cell. An application can be use this to capture the state of the button (on, off, flashing, etc.) in relation to, but independent from the button-press (trigger) action.