### Initialize Engine and Setup Polls Source: https://monome.org/docs/norns/engine-study-3/engine-study-3.lua Initializes the engine, sets up brightness and amplitude polls for dynamic parameter updates, and starts a redraw timer for 60fps screen updates. ```lua function init() -- NEW: invoke our brightness poll // brightness = poll.set("brightness_poll") brightness.callback = function(val) bright = util.round(util.linlin(20, 20000, 1, 15, val)) screen_dirty = true end brightness.time = 1 / 60 brightness:start() -- // brightness poll -- NEW: invoke our amp poll // amp = poll.set("amp_poll") amp.callback = function(val) rad = util.round(util.linlin(0, 1, 2, 120, val)) screen_dirty = true end amp.time = 1 / 30 amp:start() -- // amp poll -- NEW: redraw at 60fps // redraw_timer = metro.init(function() if screen_dirty then redraw() screen_dirty = false end end, 1 / 60, -1) redraw_timer:start() -- // redraw -- NEW: synth controls // params:add({ type = "separator", id = "synth_separator", name = "synth", }) params:add({ type = "control", id = "fchz", name = "filter hz", controlspec = controlspec.FREQ, action = function(x) if fchzLFO.enabled == 0 then engine.set_synth("fchz", x) end fchz_raw = params:get_raw("fchz") end, }) -- // synth controls ``` -------------------------------- ### Install libmonome Dependencies and Compile Source: https://monome.org/docs/serialosc/source Installs the required libraries for libmonome and then clones, configures, builds, and installs libmonome itself. ```bash sudo apt-get install liblo-dev libudev-dev git clone https://github.com/monome/libmonome.git cd libmonome ./waf configure ./waf sudo ./waf install cd .. ``` -------------------------------- ### Run diii CLI Source: https://monome.org/docs/iii/diii-cli Activates the virtual environment and starts the diii command-line interface. Navigate to the installation directory first. ```bash cd ~/diii source .venv/bin/activate diii ``` -------------------------------- ### Install serialosc Dependencies and Compile Source: https://monome.org/docs/serialosc/source Installs the required libraries for serialosc and then clones, configures, builds, and installs serialosc. ```bash sudo apt-get install libavahi-compat-libdnssd-dev libuv1-dev git clone https://github.com/monome/serialosc.git --recursive cd serialosc ./waf configure ./waf sudo ./waf install cd .. ``` -------------------------------- ### Fileselect Example: Display Audio Files Only Source: https://monome.org/docs/norns/reference/lib/fileselect This example demonstrates how to use fileselect to display only audio files. It defines a callback function to process the selected file path and a key handler to trigger the fileselect interface. The `_path.audio` alias is used as the starting folder. ```lua fileselect = require('fileselect') selected_file = 'none' selected_file_path = 'none' function callback(file_path) -- this defines the callback function that is used in fileselect if file_path ~= 'cancel' then -- if a file is selected in fileselect -- the following are some common string functions to help organize the path that is returned from fileselect local split_at = string.match(file_path, "^.*()/ ") selected_file_path = string.sub(file_path, 9, split_at) selected_file_path = util.trim_string_to_width(selected_file_path, 128) selected_file = string.sub(file_path, split_at + 1) print(selected_file_path) print(selected_file) end redraw() end function redraw() screen.clear() screen.level(15) screen.move(0,10) screen.text('selected file path:') screen.move(0,20) screen.text(selected_file_path) screen.move(0,30) screen.text('selected file:') screen.move(0,40) screen.text(selected_file) screen.move(0,60) screen.text('press K3 to select file') screen.update() end function key(n,z) if n == 3 and z == 1 then fileselect.enter(_path.audio, callback, "audio") -- runs fileselect.enter; `_path.audio` in this example is the folder that will open when fileselect is run end end ``` -------------------------------- ### Basic Engine Example Source: https://monome.org/docs/norns/reference/engine A practical example demonstrating engine loading and command execution. ```APIDOC ## Basic Engine Example ### Description This example shows how to load an engine, access its commands, and control parameters over time. ### Code ```lua -- basic engine reference example engine.name = 'PolyPerc' -- loads engine and executes script's init() s = require 'sequins' function init() print(" ") print("available engines:") tab.print(engine.names) print(" ") print("loaded engine:") print(engine.name) print(" ") print("commands for "..engine.name) engine.list_commands() pan_vals = s{-1,1,0.5,-0.5,0} pw_vals = s{0.25,0.9,0.1,0.75,0.3,0.5, 0.8} cutoff_vals = s{3000,600,1200,1530,6666} base_hz = 300 hz_divs = s{1,1.5,0.5,1/3,2,0.25} clock.run( function() while true do clock.sync(1) engine.pan(pan_vals()) engine.pw(pw_vals()) engine.cutoff(cutoff_vals()) engine.release(math.random(3,300)/100) engine.hz(base_hz * hz_divs()) end end ) end ``` ``` -------------------------------- ### Install easymidi Library Source: https://monome.org/docs/grid/studies/nodejs Install the easymidi library for MIDI message handling. If you encounter installation errors, ensure you have the libasound2-dev package installed. ```bash $ npm install --save easymidi ``` -------------------------------- ### Install Seamstress with Homebrew Source: https://monome.org/docs/grid/studies/seamstress/seamstress-and-norns Use Homebrew to install Seamstress by tapping the repository and then installing the package. This is one method for setting up Seamstress. ```bash brew tap ryleelyman/seamstress brew install seamstress ``` -------------------------------- ### Create and Compare Sprocket Divisions Source: https://monome.org/docs/norns/reference/lib/lattice This example demonstrates how to create a new lattice and add multiple sprockets with different divisions to represent various note durations and time signatures. It then starts the lattice to observe the output. ```lua lattice = require("lattice") comparing_divisions = lattice:new{} -- whole notes in 5/4 whole_fivefour = comparing_divisions:new_sprocket{ action = function(t) print("~~~ whole notes in 5/4 ~~~", t) end, division = 5/4 } -- whole notes in 4/4 whole_fourfour = comparing_divisions:new_sprocket{ action = function(t) print("!! whole notes in 4/4 !!", t) end, division = 4/4 } -- quarter notes in 4/4 quarter_fourfour = comparing_divisions:new_sprocket{ action = function(t) print("< quarter notes in 4/4 >", t) end, division = 1/4 } -- eighth notes in 5/4 eighth_fivefour = comparing_divisions:new_sprocket{ action = function(t) print(">! eighth notes in 5/4 !<", t) end, division = (1/8) * (5/4) } comparing_divisions:start() ``` -------------------------------- ### List and Run Seamstress Examples Source: https://monome.org/docs/grid/studies/seamstress/seamstress-and-norns Use the '-e' flag with 'seamstress' to list available examples, and run a specific example by providing its script name after the '-e' flag. ```bash seamstress -e ``` ```bash seamstress -e SCRIPTNAME ``` -------------------------------- ### Start and Control FXBusDemo Synth Source: https://monome.org/docs/norns/engine-study-3 Provides example code to instantiate the FXBusDemo synth, set initial levels and panning for delay and reverb sends, and then control the isolator's frequency band amplitudes. ```sc // start the synth: ( Routine{ x = FXBusDemo.new(330*0.75); x.setLevel(\delay_send,0.6); x.setLevel(\reverb_send,0.6); x.setPan(\delay_send,-1); x.setPan(\reverb_send,1); }.play; ) // control the isolator: x.setMain(\ampLo,0); x.setMain(\ampMid,0); x.setMain(\ampHi,0); x.setMain(\ampLo,1); x.setMain(\ampMid,1); x.setMain(\ampHi,1); ``` -------------------------------- ### start Source: https://monome.org/docs/norns/api/modules/lib.reflection.html Starts the transport, optionally syncing to a beat and offset. ```APIDOC ## start (beat_sync, offset) ### Description Starts the transport, optionally syncing to a beat and offset. ### Method N/A (Function) ### Endpoint N/A ### Parameters #### Path Parameters - **beat_sync** (number, optional) - Sync playback start to beat value. - **offset** (number, optional) - If set, this value will be added to the beat_sync value. ``` -------------------------------- ### start Source: https://monome.org/docs/norns/api/modules/lib.pattern_time.html Starts the playback of the recorded pattern. ```APIDOC ## start () ### Description Starts the playback of the pattern. Events will be triggered according to their recorded timing and the current time factor. ### Method start() ### Endpoint N/A (Function call) ### Parameters None ### Response None ``` -------------------------------- ### Typing Example Source: https://monome.org/docs/norns/reference/keyboard An example demonstrating how to use `keyboard.char` for text input and `keyboard.code` for handling special keys like BACKSPACE and ENTER. ```APIDOC ```lua MU = require("musicutil") engine.name = "PolySub" my_string = "" function init() engine.ampAtk(0) engine.ampDec(0.1) engine.ampSus(0.05) engine.ampRel(0.5) end function keyboard.char(character) my_string = my_string..character -- add characters to my string redraw() end function keyboard.code(code,value) if value == 1 or value == 2 then -- 1 is down, 2 is held, 0 is release if code == "BACKSPACE" then my_string = my_string:sub(1, -2) -- erase characters from my_string elseif code == "ENTER" then my_string = "" -- clear my_string note_on() -- play a bell end redraw() end end function redraw() screen.clear() screen.move(10,30) screen.text(my_string) screen.update() end function note_on() for i = 1,4 do engine.start(i,2500+(250*i/150)) end clock.run(note_off) end function note_off() clock.sleep(0.1) for i = 1,4 do engine.stop(i) end end ``` ``` -------------------------------- ### Install Script from GitHub URL Source: https://monome.org/docs/norns/maiden Install scripts directly from a GitHub repository URL using the ';install' command in the REPL. Ensure you have a WiFi connection. The script will be placed in the /home/we/dust/code directory. ```shell ;install https://github.com/tehn/test-update ``` -------------------------------- ### SSH Session Example Source: https://monome.org/docs/norns/advanced-access This is an example of a successful SSH login to a Norns device, showing the Linux version and the Norns welcome message. ```bash ssh we@norns.local Linux norns 4.19.127-16-gb1425b1 #1 SMP PREEMPT Mon Oct 26 05:39:00 UTC 2020 armv7l ___ ___ ___ ___ ___ | | . | _| |_ -| |_|_|___|_| |_|_|___| monome.org/norns 127.0.0.1 ~ $ ``` -------------------------------- ### Clock Example Source: https://monome.org/docs/norns/reference/clock An example demonstrating how to use the clock system to run a looping function. ```APIDOC ## Clock Example ### Description This example demonstrates how to start a coroutine using `clock.run` and have it execute a function repeatedly using `clock.sleep`. ### Code ```lua -- start a clock which calls function [loop] function init() clock.run(loop, "so true") -- arguments can be passed end -- this function loops forever, printing at 1 second intervals function loop(print_this) while true do print(print_this) clock.sleep(1) end end ``` ``` -------------------------------- ### Install web-druid Dependencies Source: https://monome.org/docs/crow/druid Before serving web-druid locally, install its Node.js dependencies using npm. ```bash npm install ``` -------------------------------- ### Define Transport Start/Stop Callbacks Source: https://monome.org/docs/norns/clocks Define custom functions to execute when the transport starts or stops. This example shows basic setup with a pulse function and running a coroutine. ```lua engine.name = 'PolyPerc' function pulse() clock.sync(1/4) engine.hz(333) end function clock.transport.start() print("we begin") id = clock.run(pulse) end function clock.transport.stop() clock.cancel(id) end ``` -------------------------------- ### Main Application Entry Point Source: https://monome.org/docs/libmonome/03_ripples.c Initializes the Monome device, sets up signal handling, and prepares the application data structure. Requires the device path as a command-line argument. ```c int main(int argc, char *argv[]) { monome_t *monome; double now, then; struct app_data *data; int y; if (argc < 2) { printf("Usage %s device_path\n", argv[0]); return 1; } signal(SIGINT, please_close); ``` -------------------------------- ### Install monome-grid Library Source: https://monome.org/docs/grid/studies/nodejs Install the monome-grid library, which is required for interacting with monome devices in Node.js. ```bash $ npm install --save monome-grid ``` -------------------------------- ### Set Working Pattern Start Location Source: https://monome.org/docs/teletype/manual Get or set the starting index for the working pattern. Defaults to 0. ```script P.START 2 ``` -------------------------------- ### Connect to MIDI Port and Setup Parameters Source: https://monome.org/docs/grid/studies/seamstress Connects to the first virtual MIDI port and sets up parameters for root note and scale selection using the musicutil library. Bangs the parameters to initialize their actions. ```lua -- NEW // -- we'll connect to virtual port 1, which is seamstress's MIDI device: m = midi.connect(1) -- for a more robust example of MIDI scaffolding, -- check out the 'hello_midi' example! active_notes = {} -- to keep track of 'note on' messages, for paired 'note off' -- build scales for quantized note selection: scale_names = {} for i = 1, #MU.SCALES do table.insert(scale_names, string.lower(MU.SCALES[i].name)) end params:add_control( "root_note", -- scripting ID "root note", -- UI name controlspec.new(0, 127, "lin", 1, 72, nil, 1 / 127), -- controlspec function(param) -- UI formatter return MU.note_num_to_name(param:get(), true) end ) params:set_action("root_note", function() build_scale() end) params:add_option("scale", "scale", scale_names, 5) params:set_action("scale", function() build_scale() end) -- important! since our script relies on the output of our parameter actions, -- we'll want to fire them off in the init: params:bang() -- // NEW ``` -------------------------------- ### Set Specific Pattern Start Location Source: https://monome.org/docs/teletype/manual Get or set the starting index for a specific pattern number. Defaults to 0. ```script PN.START 0 3 ``` -------------------------------- ### Set up Blackfin Toolchain Source: https://monome.org/docs/aleph/dev/dsp Download and unpack the Blackfin GCC toolchain, then add its binaries to your PATH. This is necessary for compiling DSP modules. ```bash cd ~/Downloads su tar -xjvf blackfin-toolchain-elf-gcc-4.3-2014R1-RC2.x86_64.tar.bz2 export PATH=$PATH:/opt/uClinux/bfin-elf/bin ``` -------------------------------- ### Norns Missing Engine Error Example Source: https://monome.org/docs/norns/help/software This error signifies that a script requires an engine that is not installed. Install the missing engine via the Project Manager. ```text ### SCRIPT ERROR: missing Timber ``` -------------------------------- ### Main Application Initialization Source: https://monome.org/docs/iii/library/archive/ribbons.lua Calls the init function to set up the application, including timers and initial state. ```lua init() ``` -------------------------------- ### Start Playback Source: https://monome.org/docs/norns/reference/lib/reflection Begin playback of the recorded pattern. Optionally sync playback start to a specific beat and add an offset. ```lua my_pattern:start(beat_sync, offset) ``` -------------------------------- ### Setting up Multiple LFOs Source: https://monome.org/docs/norns/reference/lib/lfo This example demonstrates how to initialize and configure multiple LFOs for different engine parameters. It includes setting min/max values before adding parameters and defining actions for parameter changes. ```lua _lfos = require 'lfo' -- assign the library to a general variable engine.name = 'PolyPerc' s = require 'sequins' function init() hz_vals = s{400,600,200,350} sync_vals = s{1,1/3,1/2,1/6,2} clock.run(iter) screen_dirty = true -- IMPORTANT! set your LFO's 'min' and 'max' *before* adding params, so they can scale appropriately: cutoff_lfo = _lfos:add{min = 200, max = 5000} -- 14 parameters for LFOs + 1 separator for each: params:add_group('LFOs',30) -- now we can add our params cutoff_lfo:add_params('cutoff_lfo', 'cutoff') cutoff_lfo:set('action', function(scaled, raw) engine.cutoff(scaled) screen_dirty = true end) release_lfo = _lfos:add{min = 0.03, max = 2} release_lfo:add_params('release_lfo', 'release') release_lfo:set('action', function(s,r) engine.release(s) screen_dirty = true end) redraw_screen = metro.init(check_dirty,1/15,-1) redraw_screen:start() end function iter() while true do clock.sync(sync_vals()) hertz = hz_vals() engine.hz(hertz) end end function check_dirty() if screen_dirty then redraw() screen_dirty = false end end function redraw() screen.clear() screen.move(64,30) screen.font_size(8) local text_to_display = "cutoff lfo: "..(cutoff_lfo:get('depth') > 0 and (util.round(cutoff_lfo:get('scaled'),0.01)..'hz') or ("-")) screen.text_center(text_to_display) screen.move(64,50) screen.font_size(8) text_to_display = "release lfo: "..(release_lfo:get('depth') > 0 and (util.round(release_lfo:get('scaled'),0.01)..'s') or ("-")) screen.text_center(text_to_display) screen.update() end ``` -------------------------------- ### Quantizer Setup: Define Scale Source: https://monome.org/docs/teletype/studies-7 Set the desired quantization scale using the 'X' variable. This example defines a whole tone scale. ```teletype X N 2 ``` -------------------------------- ### Softcut Basic Playback and Recording Setup Source: https://monome.org/docs/norns/softcut This snippet demonstrates the essential parameters to set up a voice for looping playback and recording. It covers enabling the voice, assigning a buffer, setting the level, defining loop points, and initiating playback. ```APIDOC ## Softcut Parameters for Looping ### Description Sets up a voice for looping playback and recording. This includes enabling the voice, assigning a buffer, setting the volume level, defining the start and end points of the loop, setting the current playback position, and starting playback. ### Methods - `softcut.enable(voice, value)`: Enables or disables a voice. `value` is typically 1 to enable. - `softcut.buffer(voice, buffer_index)`: Assigns a buffer to a voice. `buffer_index` is the buffer number. - `softcut.level(voice, value)`: Sets the playback level for a voice. `value` is a float between 0.0 and 1.0. - `softcut.loop(voice, value)`: Enables or disables looping for a voice. `value` is typically 1 to enable. - `softcut.loop_start(voice, position)`: Sets the start point of the loop in seconds. - `softcut.loop_end(voice, position)`: Sets the end point of the loop in seconds. - `softcut.position(voice, position)`: Sets the current playback position in seconds. - `softcut.play(voice, value)`: Starts or stops playback for a voice. `value` is typically 1 to start. ### Example Usage ```lua softcut.enable(1, 1) softcut.buffer(1, 1) softcut.level(1, 1.0) softcut.loop(1, 1) softcut.loop_start(1, 1) softcut.loop_end(1, 2) softcut.position(1, 1) softcut.play(1, 1) ``` ``` -------------------------------- ### Advanced LFO Interaction Example Source: https://monome.org/docs/norns/reference/lib/lfo This example demonstrates building a complex LFO interaction using `:set` and `:get` methods. It includes setting LFO parameters, defining an action callback, and handling user input for engagement and adjustment. Press K3 to engage/disengage the LFO. ```lua _lfos = require 'lfo' -- assign the library to a general variable engine.name = 'PolyPerc' s = require 'sequins' function init() hz_vals = s{400,600,200,350} sync_vals = s{1,1/3,1/2,1/6,2} clock.run(iter) screen_dirty = true -- establish an LFO variable for a specific purpose: cutoff_lfo = _lfos.new() cutoff_lfo:set('shape', 'sine') cutoff_lfo:set('min', 200) cutoff_lfo:set('max', 5000) cutoff_lfo:set('depth', 0.3) cutoff_lfo:set('mode', 'free') cutoff_lfo:set('period', 2) cutoff_lfo:set('action', function(scaled,raw) engine.cutoff(scaled) screen_dirty = true end) redraw_screen = metro.init(check_dirty,1/15,-1) redraw_screen:start() end function iter() while true do clock.sync(sync_vals()) hertz = hz_vals() engine.hz(hertz) cutoff_lfo:set('depth', math.random()) end end function check_dirty() if screen_dirty then redraw() screen_dirty = false end end function redraw() screen.clear() screen.level(15) screen.move(64,40) screen.font_size(20) screen.text_center(util.round(cutoff_lfo:get('scaled'),0.01)..'hz') screen.update() end -- press K3 to start/stop: function key(n,z) if n == 3 and z == 1 then if cutoff_lfo:get('enabled') == 1 then cutoff_lfo:stop() else cutoff_lfo:start() end end end -- turn E3 to adjust cutoff when LFO is inactive: function enc(n,d) if n == 3 and cutoff_lfo:get('enabled') == 0 then local current = cutoff_lfo:get('scaled') local change = util.clamp(current + d*100, cutoff_lfo:get('min'), cutoff_lfo:get('max')) cutoff_lfo:set('scaled', change) engine.cutoff(cutoff_lfo:get('scaled')) screen_dirty = true end end ``` -------------------------------- ### dfu-util Output Example Source: https://monome.org/docs/crow/manual-update This is an example of the output you might see when the firmware update command is executed. It shows the dfu-util process and confirmation of a successful download. ```text dfu-util 0.9 Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc. Copyright 2010-2016 Tormod Volden and Stefan Schmidt This program is Free Software and has ABSOLUTELY NO WARRANTY Please report bugs to http://sourceforge.net/p/dfu-util/tickets/ dfu-util: Invalid DFU suffix signature dfu-util: A valid DFU suffix will be required in a future dfu-util release!!! Deducing device DFU version from functional descriptor length Opening DFU capable USB device... ID 0483:df11 Run-time device DFU version 011a Claiming USB DFU Interface... Setting Alternate Setting #0 ... Determining device status: state = dfuIDLE, status = 0 dfuIDLE, continuing DFU mode device DFU version 011a Device returned transfer size 1024 DfuSe interface name: "Internal Flash " Downloading to address = 0x08020000, size = 290876 Download [=========================] 100% 290876 bytes Download done. File downloaded successfully dfu-util: can't detach Resetting USB to switch back to runtime mode ``` -------------------------------- ### Example: Selectable MIDI Device Targeting Source: https://monome.org/docs/norns/reference/midi Demonstrates how to connect to multiple MIDI devices, list them as selectable options, and send MIDI note events to a selected device using key presses. ```lua function init() midi_device = {} -- container for connected midi devices midi_device_names = {} target = 1 key3_hold = false random_note = math.random(48,72) for i = 1,#midi.vports do -- query all ports midi_device[i] = midi.connect(i) -- connect each device table.insert( -- register its name: midi_device_names, -- table to insert to "port "..i..": "..util.trim_string_to_width(midi_device[i].name,80) -- value to insert ) end params:add_option("midi target", "midi target",midi_device_names,1) params:set_action("midi target", function(x) target = x end) end function enc(n,d) if n == 2 then if #midi_device > 0 then params:delta("midi target",d) redraw() end end end function key(n,z) if n == 3 then if z == 1 then midi_device[target]:note_on(random_note) -- defaults to velocity 100 on ch 1 key3_hold = true redraw() elseif z == 0 then midi_device[target]:note_off(random_note) random_note = math.random(50,70) key3_hold = false redraw() end end end function redraw() screen.clear() screen.move(0,10) screen.text(params:string("midi target")) screen.move(0,30) if not key3_hold then screen.text("press K3 to send note "..random_note) else screen.text("release K3 to end note "..random_note) end screen.update() end ``` -------------------------------- ### Looping Coroutine Example Source: https://monome.org/docs/norns/reference/clock Demonstrates starting a coroutine that loops indefinitely, printing a message and sleeping for 1 second between iterations. Arguments can be passed to the coroutine. ```lua -- start a clock which calls function [loop] function init() clock.run(loop,"so true") -- arguments can be passed end -- this function loops forever, printing at 1 second intervals function loop(print_this) while true do print(print_this) clock.sleep(1) end end ``` -------------------------------- ### SuperCollider REPL Output Example Source: https://monome.org/docs/norns/maiden This output shows a common SuperCollider error related to duplicate engine classes. It helps identify conflicting engine installations. ```log compiling class library... Found 738 primitives. Compiling directory '/usr/local/share/SuperCollider/SCClassLibrary' Compiling directory '/usr/local/share/SuperCollider/Extensions' Compiling directory '/home/we/.local/share/SuperCollider/Extensions' Compiling directory '/home/we/norns/sc/core' Compiling directory '/home/we/norns/sc/engines' Compiling directory '/home/we/dust' ERROR: duplicate Class found: 'Engine_PolyPerc' /home/we/norns/sc/engines/Engine_PolyPerc.sc /home/we/dust/code/other-stuff-i-installed/PolyPerc.sc ERROR: There is a discrepancy. numClassDeps 1517 gNumClasses 3032 ``` -------------------------------- ### Create and Manage UI Lists Source: https://monome.org/docs/norns/reference/lib/ui/list Demonstrates creating multiple UI list instances with different entries and managing their display. It shows how to set index deltas with and without wrapping, and how to update the screen based on list selections. ```lua UI = require("ui") -- create lists of entries emotions = {'happy', 'angry', 'sad'} places = {'park', 'pool', 'school'} times = {'morning', 'afternoon','evening'} -- creates instances of lists list = {} list[1] = UI.List.new(0,34,1,emotions) list[2] = UI.List.new(40,34,2,places) list[3] = UI.List.new(80,34,3,times) function redraw() screen.clear() screen.font_size(8) for i=1,3 do -- redraw three lists list[i]:redraw() end screen.move(0,8) screen.level(15) screen.text('i was '..emotions[list[1].index]..' at the '..places[list[2].index]) screen.move(0,16) screen.text('in the '..times[list[3].index]..'.') screen.update() end function enc(n,d) if n == 1 then list[1]:set_index_delta(d,false) -- sets index according to delta of E1, no wrapping elseif n == 2 then list[2]:set_index_delta(d,true) -- sets index according to delta of E2, with wrapping elseif n == 3 then list[3]:set_index_delta(d,false) -- sets index according to delta of E2, with no wrapping end redraw() end ``` -------------------------------- ### Systemd Unit for SerialOSC Service Source: https://monome.org/docs/serialosc/linux Create this systemd unit file to automatically start the serialoscd service at boot when compiling from source. Ensure the ExecStart path matches your installation. ```systemd [Unit] Description=Starts serialoscd at system boot [Service] Type=simple ExecStart=/usr/local/bin/serialoscd ``` -------------------------------- ### Initialize and Configure Lattice and Sprockets Source: https://monome.org/docs/norns/reference/lib/lattice Demonstrates the creation of a default lattice and a configured lattice with custom arguments. It also shows how to create multiple sprockets with different actions, divisions, and delays, and how to start the lattice. ```lua lattice = require("lattice") function init() -- default lattice usage, with no arguments default_lattice = lattice:new() -- default lattice usage, showing default arguments my_lattice = lattice:new{ auto = true, ppqn = 96 } -- make some sprockets sprocket_a = my_lattice:new_sprocket{ action = function(t) print("whole notes", t) end, division = 1, enabled = true } sprocket_b = my_lattice:new_sprocket{ action = function(t) print("half notes", t) end, division = 1/2, delay = 0.5 } sprocket_c = my_lattice:new_sprocket{ action = function(t) print("quarter notes", t) end, division = 1/4, swing = 60 } sprocket_d = my_lattice:new_sprocket{ action = function(t) print("eighth notes", t) end, division = 1/8, enabled = false } -- start the lattice my_lattice:start() -- demo stuff screen_dirty = true redraw_clock_id = clock.run(redraw_clock) end ``` -------------------------------- ### Monome Basic Interaction Example (C) Source: https://monome.org/docs/libmonome/00_hello.c This snippet shows how to open a monome device, register a callback for button presses, and toggle LEDs. Ensure the correct device path is provided as a command-line argument. ```c #include #include #include #include #include unsigned int grid[16][16]; void handle_press(const monome_event_t *e, void *data) { unsigned int x, y; x = e->grid.x; y = e->grid.y; /* toggle the button */ grid[x][y] = !grid[x][y]; monome_led_set(e->monome, x, y, grid[x][y]); } int main(int argc, char *argv[]) { monome_t *monome; if (argc < 2) { printf("Usage %s device_path\n", argv[0]); return 1; } int x, y; for(x = 0; x < 16; x++) for(y = 0; y < 16; y++) grid[x][y] = 0; if( !(monome = monome_open(argv[1], "8000")) ) return -1; monome_led_all(monome, 0); monome_register_handler(monome, MONOME_BUTTON_DOWN, handle_press, NULL); monome_event_loop(monome); monome_close(monome); return 0; } ``` -------------------------------- ### Norns Textentry Example Source: https://monome.org/docs/norns/reference/lib/textentry Demonstrates how to use textentry.enter to get user input for both UI strings and parameters. Includes callback functions for handling input and a check function for validation. ```lua textentry = require('textentry') my_string_1 = "replace me by pressing K3" my_string_2 = "replace me in params" function init() params:add_trigger('change_string_2', 'change string 2 here') params:set_action('change_string_2', function() textentry.enter(callback_2,my_string_2) end) end function callback_1(txt) if txt ~= nil and check(txt) ~= "too long" then my_string_1 = txt end redraw() end function callback_2(txt) if txt ~= nil then my_string_2 = txt end redraw() end function check(txt) if string.len(txt) > 10 then return "too long" else return ("remaining: "..10 - string.len(txt)) end end function redraw() screen.clear() screen.move(0,30) screen.text(my_string_1) screen.move(0,40) screen.text(my_string_2) screen.update() end function key(n,z) if n == 3 and z == 1 then local default_text = my_string_1 ~= "replace me by pressing K3" and my_string_1 or "" textentry.enter(callback_1,default_text,"enter 10 chars or less", check) end end ``` -------------------------------- ### Install Raspberry Pi Boot Drivers on Windows Source: https://monome.org/docs/norns/help/data For first-time installations on a fresh CM3+ using Windows, you may need to install Raspberry Pi boot drivers and run `rpiboot`. Follow these instructions on the Raspberry Pi site to make the new CM3+ show up as a USB mass storage device. ```bash rpiboot ``` -------------------------------- ### Load and Initialize Engine Source: https://monome.org/docs/norns/reference/engine Assigning `engine.name` at the start of a script loads the specified SuperCollider engine. This example demonstrates loading 'PolyPerc' and then using its commands within a timed loop. ```lua -- basic engine reference example engine.name = 'PolyPerc' -- loads engine and executes script's init() s = require 'sequins' function init() print(" ") print("available engines:") tab.print(engine.names) print(" ") print("loaded engine:") print(engine.name) print(" ") print("commands for "..engine.name) engine.list_commands() pan_vals = s{-1,1,0.5,-0.5,0} pw_vals = s{0.25,0.9,0.1,0.75,0.3,0.5, 0.8} cutoff_vals = s{3000,600,1200,1530,6666} base_hz = 300 hz_divs = s{1,1.5,0.5,1/3,2,0.25} clock.run( function() while true do clock.sync(1) engine.pan(pan_vals()) engine.pw(pw_vals()) engine.cutoff(cutoff_vals()) engine.release(math.random(3,300)/100) engine.hz(base_hz * hz_divs()) end end ) end ``` -------------------------------- ### Initialize npm Project Source: https://monome.org/docs/grid/studies/nodejs Initialize a new Node.js project by creating a package.json file. Press enter to accept default values for all prompts. ```bash $ npm init ``` -------------------------------- ### Sequencer with Transport Control Source: https://monome.org/docs/norns/clocks A comprehensive example of a basic sequencer structure that utilizes transport start and stop callbacks. It includes coroutine management, step tracking, and screen update logic. ```lua -- define what should happen when the transport starts function clock.transport.start() step = 0 -- assign a variable to a coroutine allows it to be canceled later my_sequencer = clock.run(sequence) -- keep track of the transport state: transport_active = true screen_dirty = true end -- define what should happen when the transport stops function clock.transport.stop() clock.cancel(my_sequencer) transport_active = false end -- this function loops until canceled by clock.transport.stop() -- it advances the sequencer by one step every 1/16th note function sequence() if params:string("clock_source") ~= "midi" then clock.sync(4) -- wait until the "1" of a 4/4 count end while true do step = util.wrap(step + 1,1,16) if step == 1 then print(clock.get_beats()) end screen_dirty = true clock.sync(1/4) -- in 4/4, 1 beat is a quarter note, so sixteenths = 1/4 of a beat end end function init() -- clock.run doesn't always need to be pointed to external functions! -- here, we define a screen redraw coroutine inside of our clock.run: screen_redraw_clock = clock.run( function() while true do clock.sleep(1/30) -- 30 fps if screen_dirty == true then redraw() screen_dirty = false end end end ) step = 0 screen_dirty = true end function key(n,z) -- since MIDI and Link offer their own start/stop messages, -- we'll only need to manually start if using internal or crow clock sources: if params:string("clock_source") == "internal" or params:string("clock_source") == "crow" then if n == 3 and z == 1 then if transport_active then clock.transport.stop() else clock.transport.start() end screen_dirty = true end end end function redraw() screen.clear() for i = 1,16 do screen.level(step == i and 15 or 3) screen.move(10 + (i*5),30) screen.text("|") end if params:string("clock_source") == "internal" or params:string("clock_source") == "crow" then screen.move(20,50) screen.level(15) screen.text(transport_active and "K3 to stop" or "K3 to start") end screen.update() end ``` -------------------------------- ### Arduino Setup Function for Monome Connection Source: https://monome.org/docs/grid/studies/arduino Configure the Monome controller to use a callback function for connection events and initialize the serial port for debugging. This function runs once when the Arduino sketch starts. ```cpp void setup() { monome.SetConnectCallback(&ConnectCallback); Serial.begin(115200); Serial.print("\r\ninitialized.\r\n"); delay(200); } ``` -------------------------------- ### Reflection Scripting Example Source: https://monome.org/docs/norns/reference/lib/reflection A comprehensive example demonstrating the use of the reflection library for grid-based pattern recording and playback, including custom callbacks and grid interaction. ```lua -- reflection scripting example _r = require 'reflection' -- import the library my_pattern = _r.new() -- make a pattern g = grid.connect() -- connect a grid function init() lit = {} -- lit keys for grid presses my_pattern.process = process_press -- the process which the pattern will execute upon playback initialize_parameters() -- init params grid_redraw() -- redraw the connected grid end function my_pattern.start_callback() -- user-script callback print('playback started', clock.get_beats()) playback_queued = false grid_redraw() end function my_pattern.end_of_rec_callback() -- user-script callback print('recording finished', clock.get_beats()) grid_redraw() end function my_pattern.end_of_loop_callback() -- user-script callback print('loop ended', clock.get_beats()) grid_redraw() end function my_pattern.end_callback() -- user-script callback print('playback ended') if my_pattern.loop == 0 then overdubbing = false end lit = {} grid_redraw() end -- bottom-left grid key: initialize recording / playback -- above that: loop toggle -- above that: overdub toggle function g.key(x,y,z) if x == 1 and y == g.rows then if z == 1 then if my_pattern.rec == 0 and my_pattern.queued_rec == nil and my_pattern.count == 0 then my_pattern:set_rec(hold_rec and 2 or 1, record_duration > 0 and record_duration or nil, rec_sync_value) elseif my_pattern.count > 0 and my_pattern.play == 0 then if play_sync_value ~= nil then playback_queued = true my_pattern:start(play_sync_value) else my_pattern:start() end elseif my_pattern.play == 1 then my_pattern:stop() else my_pattern:set_rec(0) end end elseif x == 1 and y == g.rows - 1 then if z == 1 then params:set("loop", params:get("loop") == 1 and 2 or 1) end elseif x == 1 and y == g.rows - 2 then if z == 1 then if my_pattern.count > 0 and my_pattern.play == 1 then overdubbing = not overdubbing my_pattern:set_rec(overdubbing and 1 or 0) end end else local event = { id = x*8 + y, x = x, y = y, z = z } my_pattern:watch(event) process_press(event) end grid_redraw() end ``` -------------------------------- ### run Source: https://monome.org/docs/norns/api/modules/script.html Loads the engine and executes any script-specified initialization functions. ```APIDOC ## run ### Description Loads the engine and executes the script-specified init function, if present. ### Method run() ``` -------------------------------- ### Control Lattice and Sprocket States Source: https://monome.org/docs/norns/reference/lib/lattice Handles user input for controlling the lattice and its sprockets. It allows toggling the entire lattice, individual sprockets, and demonstrates commented-out examples for stopping, starting, and destroying them, as well as modifying sprocket properties. ```lua function key(k, z) if z == 0 then return end if k == 2 then my_lattice:toggle() elseif k == 3 then sprocket_a:toggle() sprocket_b:toggle() sprocket_c:toggle() sprocket_d:toggle() end -- lattice controls -- my_lattice:stop() -- my_lattice:start() -- my_lattice:toggle() -- my_lattice:destroy() -- individual sprocket controls -- sprocket_a:stop() -- sprocket_a:start() -- sprocket_a:toggle() -- sprocket_a:destroy() -- sprocket_a:set_division(1/7) -- sprocket_a:set_action(function() print("change the action") end) end ```