<commit_before>(ns launchpad.core
  (:refer-clojure :exclude [update])
  (:require midi)
  (:import (javax.sound.midi Receiver
                             ShortMessage)))

(declare decode-midi coord->note color->velocity encode-midi)

(defprotocol IState
  (state [this]
    "Return the State.")
  (light [this what where [red green]]
    "Returns a new state with button what (:grid, :top, or :side)
    where ([x y], 0-indexed) is lit with color [red green]")
  (unlight [this what where]
    "Convenience for light with color [0 0]")
  (react [this reactor]
    "Return a new state with the new reactor, which is a function that
    takes [state what where velocity]. If it returns an IState, the
    Launchpad will update itself accordingly)."))

(defrecord State [grid top side reactor]
  IState
  ;; All of these are pure functions.
  (state [this] this)
  (light [this what where color]
    (if (= :grid what)
      (let [[x y] where]
        (assoc-in this [:grid x y] color))
      (assoc-in this [what where] color)))
  (unlight [this what where]
    (.light this what where [0 0]))
  (react [this f]
    (assoc-in this [:reactor] f)))

(def initial-state
  "The quintessentially quiescent Launchpad."
  (let [black [0 0]
        row (vec (repeat 8 black))]
    (map->State {:grid (vec (repeat 8 row))
                 :top row
                 :side row
                 :reactor nil})))

(defprotocol ILaunchpad
  (update [this state] "Update and render the state")
  (update-with [this f]
    "Update with a function which takes a Launchpad and returns a State")
  (reset [this]
    "Reset and update state to initial-state. Equivalent to
    (.update pad initial-state) but more efficient."))

(defrecord Launchpad [state midi-in midi-out]
  IState
  (state [this] @state)
  ;; These are not pure, they perform the actions, and they return the
  ;; Launchpad for easy threading (->)
  (light [this what where color]
    (.update this (.light (.state this) what where color)))
  (unlight [this what where]
    (.light this what where [0 0]))
  (react [this f]
    (.update this (.react (.state this) f)))
  
  ILaunchpad
  (update [this newstate]
    ;; The Launchpad Mini, and probably therefore the S, updates quickly
    ;; enough not to warrant double-buffering here, so I haven't
    ;; implemented it. But if flickering becomes an issue, that's an
    ;; option.
    (let [oldstate state<commit_msg>Fixed Launchpad.update<commit_after>(ns launchpad.core
  (:refer-clojure :exclude [update])
  (:require midi)
  (:import (javax.sound.midi Receiver
                             ShortMessage)))

(declare decode-midi coord->note color->velocity encode-midi)

(defprotocol IState
  (state [this]
    "Return the State.")
  (light [this what where [red green]]
    "Returns a new state with button what (:grid, :top, or :side)
    where ([x y], 0-indexed) is lit with color [red green]")
  (unlight [this what where]
    "Convenience for light with color [0 0]")
  (react [this reactor]
    "Return a new state with the new reactor, which is a function that
    takes [state what where velocity]. If it returns an IState, the
    Launchpad will update itself accordingly)."))

(defrecord State [grid top side reactor]
  IState
  ;; All of these are pure functions.
  (state [this] this)
  (light [this what where color]
    (if (= :grid what)
      (let [[x y] where]
        (assoc-in this [:grid x y] color))
      (assoc-in this [what where] color)))
  (unlight [this what where]
    (.light this what where [0 0]))
  (react [this f]
    (assoc-in this [:reactor] f)))

(def initial-state
  "The quintessentially quiescent Launchpad."
  (let [black [0 0]
        row (vec (repeat 8 black))]
    (map->State {:grid (vec (repeat 8 row))
                 :top row
                 :side row
                 :reactor nil})))

(defprotocol ILaunchpad
  (update [this state] "Update and render the state")
  (update-with [this f]
    "Update with a function which takes a Launchpad and returns a State")
  (reset [this]
    "Reset and update state to initial-state. Equivalent to
    (.update pad initial-state) but more efficient."))

(defrecord Launchpad [state midi-in midi-out]
  IState
  (state [this] @state)
  ;; These are not pure, they perform the actions, and they return the
  ;; Launchpad for easy threading (->)
  (light [this what where color]
    (.update this (.light (.state this) what where color)))
  (unlight [this what where]
    (.light this what where [0 0]))
  (react [this f]
    (.update this (.react (.state this) f)))
  
  ILaunchpad
  (update [this newstate]
    ;; The Launchpad Mini, and probably therefore the S, updates quickly
    ;; enough not to warrant double-buffering here, so I haven't
    ;; implemented it. But if flickering becomes an issue, that's an
    ;; option.
    (let [oldstate (.state this)
{'fraction_non_alphanumeric': 0.1145211122554068, 'fraction_numerical': 0.004531410916580845, 'mean_word_length': 2.9192897497982244, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5180146', 'n_tokens_mistral': 1554, 'n_tokens_neox': 1469, 'n_words': 623}