presets.ttl 38.1 KB
Newer Older
1
# Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
Hanspeter Portner's avatar
Hanspeter Portner committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15
#
# This is free software: you can redistribute it and/or modify
# it under the terms of the Artistic License 2.0 as published by
# The Perl Foundation.
#
# This source is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Artistic License 2.0 for more details.
#
# You should have received a copy of the Artistic License 2.0
# along the source as a COPYING file. If not, obtain it from
# http://www.perlfoundation.org/artistic_license_2_0.

Hanspeter Portner's avatar
Hanspeter Portner committed
16 17 18 19 20 21 22 23 24
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix pset: <http://lv2plug.in/ns/ext/presets#> .
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix state: <http://lv2plug.in/ns/ext/state#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
Hanspeter Portner's avatar
Hanspeter Portner committed
25

Hanspeter Portner's avatar
Hanspeter Portner committed
26 27
@prefix moony: <http://open-music-kontrollers.ch/lv2/moony#> .
@prefix lic: <http://opensource.org/licenses/> .
28
@prefix stateR: <urn:uuid:ecc34531-c5a5-4fd4-9edf-14f2d8cf7b57#> .
Hanspeter Portner's avatar
Hanspeter Portner committed
29 30 31

# to please sord_validate
moony:code
32 33
	a lv2:Parameter ;
	rdfs:range atom:String ;
34
	rdfs:label "Lua code chunk" .
35
moony:state
36 37
	a lv2:Parameter ;
	rdfs:range atom:Atom ;
38
	rdfs:label "Lua code state" .
39
moony:editorHidden
40 41
	a lv2:Parameter ;
	rdfs:range atom:Bool ;
42
	rdfs:label "Editor tab hidden state" .
43 44 45 46
moony:logHidden
	a lv2:Parameter ;
	rdfs:range atom:Bool ;
	rdfs:label "Log tab hidden state" .
47 48 49 50
moony:logFollow
	a lv2:Parameter ;
	rdfs:range atom:Bool ;
	rdfs:label "Log follow state" .
51 52 53 54
moony:logReset
	a lv2:Parameter ;
	rdfs:range atom:Bool ;
	rdfs:label "Log reset state" .
55
moony:paramHidden
56 57
	a lv2:Parameter ;
	rdfs:range atom:Bool ;
58 59
	rdfs:label "Parameter tab hidden state" .
moony:paramCols
60 61
	a lv2:Parameter ;
	rdfs:range atom:Int ;
62 63
	rdfs:label "Parameter tab columns" .
moony:paramRows
64 65
	a lv2:Parameter ;
	rdfs:range atom:Int ;
66
	rdfs:label "Parameter tab rows" .
67

68
stateR:pBool
69 70 71
	a lv2:Parameter ;
	rdfs:label "A Bool" ;
	rdfs:range atom:Bool .
72
stateR:pChunk
73 74 75
	a lv2:Parameter ;
	rdfs:label "A Chunk" ;
	rdfs:range atom:Chunk .
76
stateR:pEnum
77 78 79
	a lv2:Parameter ;
	rdfs:label "An Enum" ;
	rdfs:range atom:Int .
80
stateR:pFloat
81 82 83
	a lv2:Parameter ;
	rdfs:label "A Float" ;
	rdfs:range atom:Float .
84
stateR:pInt
85 86 87
	a lv2:Parameter ;
	rdfs:label "An Int" ;
	rdfs:range atom:Int .
88
stateR:pString
89 90 91
	a lv2:Parameter ;
	rdfs:label "A String" ;
	rdfs:range atom:String .
92
stateR:pURID
93 94 95
	a lv2:Parameter ;
	rdfs:label "A URID" ;
	rdfs:range atom:URI .
Hanspeter Portner's avatar
Hanspeter Portner committed
96

97
moony:bank-through_control-through
98 99
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
Hanspeter Portner's avatar
Hanspeter Portner committed
100
	state:state [
101
		moony:editorHidden false ;
102
		moony:logHidden true ;
103
		moony:logFollow true ;
104
		moony:logReset false ;
105 106
		moony:paramHidden true ;
		moony:paramCols 3 ;
107
		moony:paramRows 4 ;
108
		moony:code """function run(n, control, notify, ...)
Hanspeter Portner's avatar
Hanspeter Portner committed
109 110 111 112
	return ...
end"""
	] .

113
moony:bank-through_atom-through
114 115
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
Hanspeter Portner's avatar
Hanspeter Portner committed
116
	state:state [
117
		moony:editorHidden false ;
118
		moony:logHidden true ;
119
		moony:logFollow true ;
120
		moony:logReset false ;
121 122
		moony:paramHidden true ;
		moony:paramCols 3 ;
123
		moony:paramRows 4 ;
124
		moony:code """function run(n, control, notify, seq, forge, ...)
Hanspeter Portner's avatar
Hanspeter Portner committed
125
	for frames, atom in seq:foreach() do
Hanspeter Portner's avatar
Hanspeter Portner committed
126
		forge:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
127 128 129 130 131 132
	end

	return ...
end"""
	] .

133
moony:bank-through_atom-through2
134 135
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
Hanspeter Portner's avatar
Hanspeter Portner committed
136
	state:state [
137
		moony:editorHidden false ;
138
		moony:logHidden true ;
139
		moony:logFollow true ;
140
		moony:logReset false ;
141 142
		moony:paramHidden true ;
		moony:paramCols 3 ;
143
		moony:paramRows 4 ;
144
		moony:code """function run(n, control, notify, seq1, forge1, seq2, forge2)
Hanspeter Portner's avatar
Hanspeter Portner committed
145
	for frames, atom in seq1:foreach() do
Hanspeter Portner's avatar
Hanspeter Portner committed
146
		forge1:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
147 148 149
	end

	for frames, atom in seq2:foreach() do
Hanspeter Portner's avatar
Hanspeter Portner committed
150
		forge2:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
151 152 153 154
	end
end"""
	] .

155
moony:bank-through_atom-through4
156 157
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
Hanspeter Portner's avatar
Hanspeter Portner committed
158
	state:state [
159
		moony:editorHidden false ;
160
		moony:logHidden true ;
161
		moony:logFollow true ;
162
		moony:logReset false ;
163 164
		moony:paramHidden true ;
		moony:paramCols 3 ;
165
		moony:paramRows 4 ;
166
		moony:code """function run(n, control, notify, seq1, forge1, seq2, forge2, seq3, forge3, seq4, forge4)
Hanspeter Portner's avatar
Hanspeter Portner committed
167
	for frames, atom in seq1:foreach() do
Hanspeter Portner's avatar
Hanspeter Portner committed
168
		forge1:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
169 170 171
	end

	for frames, atom in seq2:foreach() do
Hanspeter Portner's avatar
Hanspeter Portner committed
172
		forge2:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
173 174 175
	end

	for frames, atom in seq3:foreach() do
Hanspeter Portner's avatar
Hanspeter Portner committed
176
		forge3:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
177 178 179
	end

	for frames, atom in seq4:foreach() do
Hanspeter Portner's avatar
Hanspeter Portner committed
180
		forge4:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
181 182 183 184
	end
end"""
	] .

185
moony:bank-multiplex_atom-multiplex2
186 187
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
Hanspeter Portner's avatar
Hanspeter Portner committed
188
	state:state [
189
		moony:editorHidden false ;
190
		moony:logHidden true ;
191
		moony:logFollow true ;
192
		moony:logReset false ;
193 194
		moony:paramHidden true ;
		moony:paramCols 3 ;
195
		moony:paramRows 4 ;
196
		moony:code """function run(n, control, notify, seq1, forge1, seq2, forge2)
197
	for frames, atom in seq1:foreach(seq2) do
Hanspeter Portner's avatar
Hanspeter Portner committed
198 199
		forge1:time(frames):atom(atom)
		forge2:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
200 201 202 203
	end
end"""
	] .

204
moony:bank-multiplex_atom-multiplex4
205 206
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
Hanspeter Portner's avatar
Hanspeter Portner committed
207
	state:state [
208
		moony:editorHidden false ;
209
		moony:logHidden true ;
210
		moony:logFollow true ;
211
		moony:logReset false ;
212 213
		moony:paramHidden true ;
		moony:paramCols 3 ;
214
		moony:paramRows 4 ;
215
		moony:code """function run(n, control, notify, seq1, forge1, seq2, forge2, seq3, forge3, seq4, forge4)
216
	for frames, atom in seq1:foreach(seq2, seq3, seq4) do
Hanspeter Portner's avatar
Hanspeter Portner committed
217 218 219 220
		forge1:time(frames):atom(atom)
		forge2:time(frames):atom(atom)
		forge3:time(frames):atom(atom)
		forge4:time(frames):atom(atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
221 222 223 224
	end
end"""
	] .

225
moony:bank-midi_midi-responder
226 227
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
Hanspeter Portner's avatar
Hanspeter Portner committed
228
	state:state [
229
		moony:editorHidden false ;
230
		moony:logHidden true ;
231
		moony:logFollow true ;
232
		moony:logReset false ;
233 234
		moony:paramHidden true ;
		moony:paramCols 3 ;
235
		moony:paramRows 4 ;
236
		moony:code """local midiR = MIDIResponder({
237
	[MIDI.NoteOn] = function(self, frames, forge, chan, note, vel)
238
		forge:time(frames):midi(MIDI.NoteOn | chan, note, vel)
Hanspeter Portner's avatar
Hanspeter Portner committed
239
	end,
240
	[MIDI.NoteOff] = function(self, frames, forge, chan, note, vel)
241
		forge:time(frames):midi(MIDI.NoteOff | chan, note, vel)
Hanspeter Portner's avatar
Hanspeter Portner committed
242
	end
243
})
Hanspeter Portner's avatar
Hanspeter Portner committed
244

245
function run(n, control, notify, seq, forge)
Hanspeter Portner's avatar
Hanspeter Portner committed
246
	for frames, atom in seq:foreach() do
247
		local handled = midiR(frames, forge, atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
248 249 250 251
	end
end"""
	] .

252
moony:bank-time_midi-sequencer
253 254
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
255
	state:state [
256
		moony:editorHidden false ;
257
		moony:logHidden true ;
258
		moony:logFollow true ;
259
		moony:logReset false ;
260 261
		moony:paramHidden true ;
		moony:paramCols 3 ;
262
		moony:paramRows 4 ;
263
		moony:code """local timeR = TimeResponder({
264 265 266
  [Time.speed] = function(self, frames, forge, speed)
    self.rolling = speed > 0.0
    if not self.rolling and forge then
267 268
      forge:time(frames):midi(MIDI.Controller, MIDI.AllNotesOff)
    end
269
  end,
270 271
  [Time.barBeat] = function(self, frames, forge, barBeat)
    if self.rolling and forge and math.tointeger(barBeat) then
272 273 274 275 276
      forge:time(frames):midi(MIDI.NoteOff, 24, 0x7f)
      forge:time(frames):midi(MIDI.NoteOn, 24, 0x7f)
    end
  end,
  [Time.bar] = function(self, frames, forge, bar)
277
    if self.rolling and forge and math.tointeger(bar) then
278 279 280 281 282
      forge:time(frames):midi(MIDI.NoteOff, 48, 0x7f)
      forge:time(frames):midi(MIDI.NoteOn, 48, 0x7f)
    end
  end,
  rolling = false
283
})
284

285
function stash(forge)
286
  timeR:stash(forge)
287 288 289
end

function apply(atom)
290
  timeR:apply(atom)
291 292
end

293
function run(n, control, notify, seq, forge)
294
  local from = 0
295
  for frames, atom in seq:foreach() do
296
    timeR(from, frames, forge, atom)
297
    from = frames
298
  end
299
  timeR(from, n, forge)
300 301 302
end"""
	] .

303 304 305 306 307 308 309
moony:bank-time_lindenmayer-system
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
		moony:editorHidden false ;
		moony:logHidden false ;
		moony:logFollow true ;
310
		moony:logReset false ;
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
		moony:paramHidden true ;
		moony:paramCols 3 ;
		moony:paramRows 4 ;
		moony:code """local mtointeger = math.tointeger -- reference locally

local rolling = false -- transport state
local oldNote = nil -- currently palying note
local velocity = 0x7f -- default note-on velocity value

-- Lindenmayer pattern-rule iterator
local function iterate(pattern, rules, n)
  for i = 1, n do -- iterate n-times
    pattern = string.gsub(pattern, '.', function(c) -- replace every single character with ...
      return rules[c] or c -- ... matching rule or itself
    end)
  end
  return pattern -- resulting iterated over pattern
end

local rules = {
  ['n'] = 'n.[.n..]', -- replacement string for character 'n'
  ['.'] = '[[..n]]' -- replacement string for character '.'
}

local start = 'n' -- initial pattern
local pattern = iterate(start, rules, 4) -- pattern after 4 iterations

local refNote = Note['C#+4'] -- initial reference note
local incNote = 3 -- reference note increment in MIDI semitones

local actions = {
  ['n'] = function() -- action for character 'n'
    coroutine.yield(refNote) -- return current reference note
  end,
  ['.'] = function() -- action for character '.'
    coroutine.yield(nil) -- return nil, e.g. this note is a pause
  end,
  ['['] = function() -- action for character '['
    refNote = (refNote + incNote) & 0x7f -- increase reference note by increment
  end,
  [']'] = function() -- action for character ']'
    refNote = (refNote - incNote) & 0x7f -- decrease reference note by increment
  end
}

local nextNote = coroutine.wrap(function() -- create iterator to get action from pattern
	while true do -- enter infinite loop
    for c in string.gmatch(pattern, '.') do -- iteratore over each single character in pattern
      local action = actions[c] -- look up action for character
      if action then
        action() -- execute action if defined
      end
    end
  end
end)

local timeR = TimeResponder({
  [Time.speed] = function(self, frames, forge, speed)
    rolling = speed ~= 0.0 -- update transport state

    if not rolling and oldNote then -- if at transport stop and currently playing a note
      forge:time(frames):midi(MIDI.NoteOff, oldNote, 0x0) -- send note-off
      oldNote = nil -- invalidate oldNote
    end
  end,
  [Time.barBeat] = function(self, frames, forge, barBeat)
    if rolling and mtointeger(barBeat) then -- if transport is rolling and barBeat being a whole integer
      if oldNote then -- if currently playing a note
        forge:time(frames):midi(MIDI.NoteOff, oldNote, 0x0) -- send note-off
        oldNote = nil -- invalidate oldNote
      end

      local newNote = nextNote() -- get new note or nil from pattern iterator
      if newNote then -- if not a pause
        forge:time(frames):midi(MIDI.NoteOn, newNote, velocity) -- send note-on
        oldNote = newNote -- update currently playing note
      end
    end
  end
}, 16) -- run 16x faster than host time

function run(n, control, notify, seq, forge)
  local from = 0 -- initialize reference frame time

  for frames, atom in seq:foreach() do -- iterate over input event sequence
    timeR(from, frames, forge, atom) -- let time responder handle the event
    from = frames -- advance reference frame time
  end

  timeR(from, n, forge) -- tell time responder about remaining frames of cycle
end"""
	] .

404
moony:bank-osc_osc-responder
405 406
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
Hanspeter Portner's avatar
Hanspeter Portner committed
407
	state:state [
408
		moony:editorHidden false ;
409
		moony:logHidden true ;
410
		moony:logFollow true ;
411
		moony:logReset false ;
412 413
		moony:paramHidden true ;
		moony:paramCols 3 ;
414
		moony:paramRows 4 ;
415
		moony:code """local oscR = OSCResponder({
416 417
	['/ping'] = function(self, frames, forge, fmt, ...)
		forge:time(frames):message('/pong', fmt, ...)
418
	end,
419 420
	['/pong'] = function(self, frames, forge, fmt, ...)
		forge:time(frames):message('/ping', fmt, ...)
421
	end
422
})
Hanspeter Portner's avatar
Hanspeter Portner committed
423

424
function run(n, control, notify, seq, forge)
Hanspeter Portner's avatar
Hanspeter Portner committed
425
  for frames, atom in seq:foreach() do
426
    local handled = oscR(frames, forge, atom)
Hanspeter Portner's avatar
Hanspeter Portner committed
427 428 429
  end
end"""
	] .
430

431
moony:bank-state_state-responder
432 433
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
434
	state:state [
435
		moony:editorHidden false ;
436
		moony:logHidden true ;
437
		moony:logFollow true ;
438
		moony:logReset false ;
439
		moony:paramHidden false ;
440
		moony:paramCols 3 ;
441
		moony:paramRows 4 ;
442
		moony:code """local urn = Mapper('urn:uuid:ecc34531-c5a5-4fd4-9edf-14f2d8cf7b57#')
443
local sync = false
444

445
local pLong
446
local pInt = Parameter{
447 448
  [RDFS.label] = 'Integer',
  [RDFS.comment] = 'This is an Integer',
449
  [RDFS.range] = Atom.Int,
450
  [Units.unit] = Units.hz,
451 452
  [LV2.minimum] = 0,
  [LV2.maximum] = 10,
453 454 455 456 457 458 459 460
	_value = 5,
	[Patch.Get] = function(self)
		return self._value
	end,
	[Patch.Set] = function(self, value)
		self._value = value
		pLong(value * 2)
		sync = true
461
  end
462 463
}

464
pLong = Parameter{
465 466 467 468
  [RDFS.label] = 'Long',
  [RDFS.comment] = 'This is a Long',
  [RDFS.range] = Atom.Long,
  [Units.unit] = Units.hz,
469 470
  [LV2.minimum] = pInt[LV2.minimum] * 2,
  [LV2.maximum] = pInt[LV2.maximum] * 2,
471
  [RDF.value] = pInt[RDF.value] * 2
472 473
}

474
local pDouble
475
local pFloat = Parameter{
476 477 478 479
  [RDFS.label] = 'Float',
  [RDFS.comment] = 'This is a Float',
  [RDFS.range] = Atom.Float,
  [Units.unit] = Units.m,
480 481
  [LV2.minimum] = -1.0,
  [LV2.maximum] = 1.0,
482 483 484 485 486 487 488 489 490
	_value = 0.0,
	[Patch.Get] = function(self)
		return self._value
	end,
	[Patch.Set] = function(self, value)
		self._value = value
		pDouble(value * 2)
		sync = true
	end
491 492
}

493
pDouble = Parameter{
494 495
  [RDFS.label] = 'Double',
  [RDFS.comment] = 'This is a Double',
496
  [RDFS.range] = Atom.Double,
497
  [Units.unit] = Units.m,
498 499
  [LV2.minimum] = pFloat[LV2.minimum] * 2,
  [LV2.maximum] = pFloat[LV2.maximum] * 2,
500
  [RDF.value] = pFloat[RDF.value] * 2
501 502
}

503
local pBool = Parameter{
504 505
  [RDFS.label] = 'Bool',
  [RDFS.comment] = 'This is a Boolean',
506
  [RDFS.range] = Atom.Bool,
507 508 509
  [RDF.value] = true
}

510
local pURID = Parameter{
511 512 513
  [RDFS.label] = 'URID',
  [RDFS.comment] = 'This is an URID',
  [RDFS.range] = Atom.URID,
514
	[RDF.value] = MIDI.MidiEvent
515 516
}

517
local pString = Parameter{
518 519 520 521 522 523
  [RDFS.label] = 'String',
  [RDFS.comment] = 'This is a String',
  [RDFS.range] = Atom.String,
  [RDF.value] = 'hello world'
}

524
local pChunk = Parameter{
525 526 527
  [RDFS.label] = 'Chunk',
  [RDFS.comment] = 'This is a Chunk',
  [RDFS.range] = Atom.Chunk,
528 529 530 531 532 533
  _value = string.char(0x1, 0x2, 0x3),
  [Patch.Get] = function(self)
		return self._value
	end,
	[Patch.Set] = function(self, value)
		self._value = value
534 535 536 537 538 539
    for i = 1, #value do
      print(i, string.byte(value, i))
    end
  end
}

540
local pEnum = Parameter{
541 542 543 544
  [RDFS.label] = 'Enum',
  [RDFS.comment] = 'This is an Enum',
  [RDFS.range] = Atom.Int,
  [RDF.value] = 0,
545 546 547
  [LV2.minimum] = 0,
  [LV2.maximum] = 2,
  [LV2.scalePoint] = {
548 549 550 551
    zero = 0,
    one = 1,
    two = 2
  }
552 553
}

554
local stateR = StateResponder{
555
  [Patch.writable] = {
556 557 558 559 560 561 562
    [urn.pInt] = pInt,
    [urn.pFloat] = pFloat,
    [urn.pBool] = pBool,
    [urn.pURID] = pURID,
    [urn.pString] = pString,
    [urn.pChunk] = pChunk,
    [urn.pEnum] = pEnum
563 564
  },
  [Patch.readable] = {
565 566
    [urn.pLong] = pLong,
    [urn.pDouble] = pDouble
567
  }
568
}
569

570
function save(forge)
571
  stateR:stash(forge)
572 573
end

574
function restore(atom)
575
  stateR:apply(atom)
576 577
end

578
function once(n, control, notify)
579
  stateR:register(0, notify)
580
end
581

582
function run(n, control, notify)
583
  for frames, atom in control:foreach() do
584 585 586 587
    if stateR(frames, notify, atom) and sync then
			stateR:sync(frames, notify)
			sync = false
		end
588
  end
589
end""" ;
590 591 592 593 594 595 596 597
		moony:state [
			stateR:pBool true ;
			stateR:pChunk "AQIDBAUGBw=="^^xsd:base64Binary ;
			stateR:pEnum 0 ;
			stateR:pFloat "8e-1"^^xsd:float ;
			stateR:pInt 9 ;
			stateR:pString "world hello" ;
			stateR:pURID <http://lv2plug.in/ns/ext/midi#MidiEvent>
598
		]
599
	] .
600

601 602 603 604 605 606 607
moony:bank-canvas_lv2-logo
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
		moony:editorHidden false ;
		moony:logHidden true ;
		moony:logFollow true ;
608
		moony:logReset false ;
609 610 611 612 613 614
		moony:paramHidden true ;
		moony:paramCols 3 ;
		moony:paramRows 4 ;
		moony:code """local bg = 0x00000000 -- transparent black
local fg = 0xff0066ff -- purple

615 616 617 618 619 620
local ctx = Stash()

local function render()
	ctx:tuple()

	-- background
621 622
	ctx:beginPath()
	ctx:rectangle(0.0, 0.0, 1.0, 1.0):style(bg):fill()
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669

	-- 'L'
	ctx:beginPath()
	ctx:polyLine(0.05, 0.275,
		0.05, 0.73463521816969,
		0.39996786383766, 0.73463521816969,
		0.35805418792799, 0.61981755929103,
		0.16950515672412, 0.61981755929103,
		0.16950515672412, 0.275,
		0.05, 0.275)
	ctx:closePath():style(fg):stroke()

	-- 'V'
	ctx:beginPath()
	ctx:polyLine(0.44035674587458, 0.73463521816969,
		0.27321237521861, 0.275,
		0.39612954205777, 0.275,
		0.5215250619933, 0.61980400005209,
		0.64678627651808, 0.275,
		0.76999411666921, 0.275,
		0.60269884777111, 0.73463521816969,
		0.44035674587458, 0.73463521816969)
	ctx:closePath():style(fg):stroke()

	-- '2'
	ctx:beginPath()
	ctx:moveTo(0.92679577564592, 0.33745757758451)
	ctx:curveTo(0.95, 0.37544661222032,
		0.9486097413556, 0.42890103900541, 0.91866073788306, 0.46581025262318)
	ctx:curveTo(0.87662774067075, 0.51761178520021,
		0.84865149155459, 0.52351773004551, 0.8188709443895, 0.55088574387747)
	ctx:lineTo(0.93798338878322, 0.55088574387747)
	ctx:lineTo(0.93798338878322, 0.61972641362727)
	ctx:lineTo(0.68857649440815, 0.61972641362727)
	ctx:curveTo(0.70410821191941, 0.57897193773781,
		0.71568706655441, 0.55649255812279, 0.73505227967577, 0.53436493734023)
	ctx:curveTo(0.78431409785481, 0.47807598612821,
		0.88073913173375, 0.44149338929647, 0.87483180798279, 0.39074363998918)
	ctx:curveTo(0.8731729385169, 0.37649219041461,
		0.86900905711197, 0.34385128732334, 0.80655313421425, 0.34385128732334)
	ctx:lineTo(0.7834998081023, 0.34385128732334)
	ctx:lineTo(0.80849192152801, 0.275)
	ctx:curveTo(0.88098903540187, 0.275,
		0.90879494370618, 0.30798728419169, 0.92679577564592, 0.33745757758451)
	ctx:closePath():style(fg):stroke()

	ctx:pop()
670 671
end

672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
render()

-- define single parameter
local graph = Parameter({
	[RDFS.label] = 'Graph',
	[RDFS.comment] = 'Canvas of graph as atom:Tuple',
	[RDFS.range] = Atom.Tuple,
	[RDF.value] = ctx:read()
})

local aspect = Parameter({
	[RDFS.label] = 'AspectRatio',
	[RDFS.comment] = 'Aspect ratio of canvas graph',
	[RDFS.range] = Atom.Float,
	[LV2.minimum] = 0.25,
	[LV2.maximum] = 4.0,
	[RDF.value] = 2.0
})

-- define a StateResponder object
local stateR = StateResponder({
	[Patch.readable] = {
		[Canvas.graph] = graph
	},
	[Patch.writable] = {
		[Canvas.aspectRatio] = aspect
	}
})

-- register parameters to UI
function once(n, control, notify)
	stateR:register(0, notify)
end

function run(n, control, notify)
	for frames, atom in control:foreach() do -- iterate over incoming events
		local handled = stateR(frames, notify, atom)
	end
710 711 712
end"""
	] .

713 714 715 716
moony:bank-tutorial_part-1
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
717
		moony:editorHidden false ;
718
		moony:logHidden true ;
719
		moony:logFollow true ;
720
		moony:logReset false ;
721 722
		moony:paramHidden true ;
		moony:paramCols 3 ;
723
		moony:paramRows 4 ;
724 725 726 727 728 729 730 731 732 733 734
		moony:code """-- Tutorial 1: MIDI Channel Blocker

-- define table which holds active MIDI channels
local channels = {0, 2, 4, 6}

-- derive channel mask based on active channels
local mask = 0 -- block everything
for i, v in ipairs(channels) do
	mask = mask | (1 << v) -- toggle bit of active channel
end

735
function run(n, control, notify, seq, forge)
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
	for frames, atom in seq:foreach() do -- iterate over incoming events
		local block = false -- assume a not-to-be-blocked event by default

		if atom.type == MIDI.MidiEvent then -- check for MIDI message
			local msg = atom[1] -- get first MIDI byte
			local cmd = msg & 0xf0 -- get MIDI command nibble
			local chn = msg & 0x0f -- get MIDI channel nibble

			if (cmd ~= 0xf0) and ((1 << chn) & mask == 0) then
				block = true -- if not a system message and channel not part of mask
			end
		end

		if not block then -- let atom through
			forge:time(frames):atom(atom) -- serialize atom as-is
		end
	end
end"""
	] .

moony:bank-tutorial_part-2
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
760
		moony:editorHidden false ;
761
		moony:logHidden true ;
762
		moony:logFollow true ;
763
		moony:logReset false ;
764 765
		moony:paramHidden true ;
		moony:paramCols 3 ;
766
		moony:paramRows 4 ;
767
		moony:code """-- Tutorial 2: MIDI Chorder
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790

-- define table that holds number of chord notes and their offsets
local chord = {0, 12, 24, 36} -- octaves, obviously

-- define a general note responder factory
local function noteResponder(cmd)
	return function (self, frames, forge, chan, note, vel)
		for i, v in ipairs(chord) do -- iterate over chord offsets
			local chanNew = i - 1 -- set MIDI channel to chord index - 1
			local noteNew = note + v -- set MIDI note to chord offset
			if noteNew >= 0 and noteNew <= 0x7f then -- handle note under/overflows
				forge:time(frames):midi(cmd | chanNew, noteNew, vel) -- serialize event
			end
		end
	end
end

-- define a MIDIResponder object configured to pass-through unmatched messages
local midiR = MIDIResponder({
	[MIDI.NoteOn] = noteResponder(MIDI.NoteOn), -- create responder for NoteOn
	[MIDI.NoteOff] = noteResponder(MIDI.NoteOff), -- and NoteOff
	[MIDI.NotePressure] = noteResponder(MIDI.NotePressure) -- and NotePressure
}, true)
791

792
function run(n, control, notify, seq, forge)
793 794 795 796 797 798 799 800 801 802
	for frames, atom in seq:foreach() do -- iterate over incoming events
		local handled = midiR(frames, forge, atom) -- call responder for event
	end
end"""
	] .

moony:bank-tutorial_part-3
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
803
		moony:editorHidden false ;
804
		moony:logHidden true ;
805
		moony:logFollow true ;
806
		moony:logReset false ;
807 808
		moony:paramHidden true ;
		moony:paramCols 3 ;
809
		moony:paramRows 4 ;
810 811
		moony:code """-- Tutorial 3: MIDI Sample & Hold

812
local urn = Mapper('urn:uuid:03340863-7f87-4f67-9fc9-9cac49c2dfba3#') -- prefix of this presets URIs
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
local sample = false -- flag to tell whether we are sampling or not
local noteOffs = {} -- table to store NoteOff events while sampling

-- MIDI responder for NoteOff events
local function noteOff(self, frames, forge, chan, note, vel)
	local msg = string.char(MIDI.NoteOff | chan, note, vel) -- encode to byte string

	if sample then -- are we sampling?
		table.insert(noteOffs, msg) -- add event to table, e.g. put it on-hold
	else
		forge:time(frames):midi(msg) -- let event through as-is
	end
end

-- MIDI responder for Controller events
local function controller(self, frames, forge, chan, control, value)
	if control == MIDI.SustainPedal then -- check for SustainPedal
		local newSample = value > 0 -- derive new sampling state from Controller value

		if newSample ~= sample then -- is new sampling state different from current one?
			if not newSample then -- sustain pedal has been released
				for i, msg in ipairs(noteOffs) do -- release NoteOff events on-hold
					forge:time(frames):midi(msg)
				end
				noteOffs = {} -- clear table as events have been released
			end

			sample = newSample -- update sampling state
		end
	else -- let through non-SustainPedal Controller events
		forge:time(frames):midi(MIDI.Controller | chan, control, value)
	end
end

-- define a MIDIResponder object configured to pass-through unmatched messages
local midiR = MIDIResponder({
	[MIDI.NoteOff] = noteOff, -- register NoteOff responder
	[MIDI.Controller] = controller -- register Controller responder
}, true)

-- push sampling state and events on-hold on stash
function stash(forge)
	local obj = forge:object() -- create object

	-- add boolean property for sampling state to object
	obj:key(urn.sample):bool(sample)

	-- add tuple property for events on-hold to object
	local tup = forge:key(urn.noteOffs):tuple()
	for i, msg in ipairs(noteOffs) do -- add events on-hold to tuple
		tup:midi(msg)
	end

	tup:pop() -- finalize tuple
	obj:pop() -- finalize object
end

-- pop sampling state and events on-hold from stash
function apply(atom)
	-- get sampling state from object
	if atom[urn.sample] then
		sample = atom[urn.sample].body
	end

	-- get events on-hold from object
	if atom[urn.noteOffs] then
		noteOffs = {} -- clear table
		for i, msg in atom[urn.noteOffs]:foreach() do -- iterate tuple
			noteOffs[i] = msg -- add events on-hold to table
		end
	end
end

886
function run(n, control, notify, seq, forge)
887 888 889 890 891
	for frames, atom in seq:foreach() do -- iterate over incoming events
		local handled = midiR(frames, forge, atom) -- call responder for event
	end
end"""
	] .
892 893 894 895 896

moony:bank-tutorial_part-4
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
897
		moony:editorHidden false ;
898
		moony:logHidden true ;
899
		moony:logFollow true ;
900
		moony:logReset false ;
901 902
		moony:paramHidden true ;
		moony:paramCols 3 ;
903
		moony:paramRows 4 ;
904 905 906 907 908 909 910 911
		moony:code """-- Tutorial 4: MIDI Arpeggiator

local schar = string.char -- local variable is more efficient to look up

local chord = {0, 3, 7, 11} -- table with chord note offsets
local offset = 0.1 -- time offset between notes in seconds

local schedule = {} -- table to store Note events
912
local dur = math.floor(offset * Options[Param.sampleRate].body) -- time offset in frames
913 914 915 916 917 918 919 920 921 922 923 924 925

-- compare function to sort scheduled messages according to frame time
local function cmp(a, b)
	return a[1] < b[1]
end

local function note_responder(cmd)
	return function(self, frames, forge, chan, note, vel)
		for i, v in ipairs(chord) do
			local chanNew = i - 1 -- set new channel to chord note index - 1
			local noteNew = note + v -- set new note to chord note offset
			local msg = schar(cmd | chanNew, noteNew, vel) -- serialize message
			local off = frames + (i-1)*dur
926
			table.insert(schedule, {off, msg}) -- schedule message with offset
927
		end
928
		table.sort(schedule, cmp) -- sort table
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
	end
end

-- define a MIDIResponder object configured to pass-through unmatched messages
local midiR = MIDIResponder({
	[MIDI.NoteOn] = note_responder(MIDI.NoteOn), -- register responder for NoteOn
	[MIDI.NoteOff] = note_responder(MIDI.NoteOff), -- and NoteOff
	[MIDI.NotePressure] = note_responder(MIDI.NotePressure) -- and NotePressure
}, true)

-- push scheduled events stash
function stash(forge)
	local seq= forge:sequence() -- create atom sequence
	for i, v in ipairs(schedule) do -- iterate over scheduled events
		seq:time(v[1]):midi(v[2]) -- add events to atom sequence
	end
	seq:pop() -- finalize atom sequence
end

-- pop scheduled events from stash
function apply(atom)
	if atom.type == Atom.Sequence then -- check for correct atom type
		schedule = {} -- clear table with scheduled events
		for off, itm in atom:foreach() do -- iteratore over sequence events
			table.insert(schedule, {off, itm.body}) -- insert event into table
		end
		table.sort(schedule, cmp) -- sort events
	end
end

-- are there any scheduled events to dispatch?
local function dispatch(n, forge)
::loop::
	for i, v in ipairs(schedule) do
		if v[1] < n then
			forge:time(v[1]):midi(v[2]) -- send message
			table.remove(schedule, i) -- remove message from scheduled events
			goto loop -- restart loop as we have removed an item
		else
			v[1] = v[1] - n -- decrease timestamp by period size
		end
	end
end

973
function run(n, control, notify, seq, forge)
974 975 976 977 978 979 980
	for frames, atom in seq:foreach() do -- iterate over incoming events
		local handled = midiR(frames, forge, atom) -- call responder for event
	end

	dispatch(n, forge) -- dispatch scheduled events
end"""
	] .
981

982 983 984 985
moony:bank-tutorial_part-5
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
986
		moony:editorHidden false ;
987
		moony:logHidden true ;
988
		moony:logFollow true ;
989
		moony:logReset false ;
990 991
		moony:paramHidden true ;
		moony:paramCols 3 ;
992
		moony:paramRows 4 ;
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
		moony:code """-- Tutorial 5: MIDI Velocity Curve Interpolator

local X = {0, 15, 112, 127} -- X-coordinates of curve
local Y = {0,  7, 120, 127} -- Y-coordinates of curve
local N = #X -- number of points to interpolate over
local Ymin = 0 -- clip minimum
local Ymax = 127 -- clip maximum

-- Lagrange Polynomial Interpolation
local function P(x)
	local sum = 0
	for j = 1, N do
		local prod = Y[j]
		for k = 1, N do
			prod = prod * (k == j and 1.0 or (x - X[k]) / (X[j] - X[k]))
		end
		sum = sum + prod
	end
	sum = math.floor(sum) -- round to lower integer
	return sum < Ymin and Ymin or (sum > Ymax and Ymax or sum) -- clip to [Ymin, Ymax]
end

-- fill velocity curve lookup table
local curve = {}
for i = 0, 127 do
	curve[i+1] = P(i)
end

-- note responder function factory
local function note_responder(cmd)
	return function(self, frames, forge, chan, note, vel)
		local velNew = curve[vel+1] -- index velocity curve lookup table
		forge:time(frames):midi(cmd | chan, note, velNew) -- send event
	end
end

-- define a MIDIResponder object configured to pass-through unmatched messages
local midiR = MIDIResponder({
	[MIDI.NoteOn] = note_responder(MIDI.NoteOn), -- register responder for NoteOn
	[MIDI.NoteOff] = note_responder(MIDI.NoteOff) -- and NoteOff
}, true)

1035
function run(n, control, notify, seq, forge)
1036 1037 1038 1039 1040 1041
	for frames, atom in seq:foreach() do -- iterate over incoming events
		local handled = midiR(frames, forge, atom) -- call responder for event
	end
end"""
	] .

1042 1043 1044 1045
moony:bank-tutorial_part-6
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
1046
		moony:editorHidden false ;
1047
		moony:logHidden true ;
1048
		moony:logFollow true ;
1049
		moony:logReset false ;
1050 1051
		moony:paramHidden true ;
		moony:paramCols 3 ;
1052
		moony:paramRows 4 ;
1053 1054
		moony:code """-- Tutorial 6: MIDI Sequencer

1055 1056

local urn = Mapper('urn:uuid:4cc65393-869d-4ca1-8ac4-fcbe902b36d6#')
1057 1058 1059

-- table with MIDI notes for 8 beats
local notes = {
1060 1061
	Note['C+4'],  -- beat 1
	Note['D#+4'], -- beat 2
1062
	false,        -- beat 3
1063 1064
	Note['C+4'],  -- beat 4
	Note['G+4'],  -- beat 5 
1065
	false,        -- beat 6
1066
	Note['G+3'],  -- beat 7
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
	false         -- beat 8
}

local vel = 0x7f -- MIDI note velocity

local active = nil -- active MIDI note

-- register Time responder object
local timeR = TimeResponder({
	rolling = false, -- flag to signal whether we are rolling or not
	[Time.speed] = function(self, frames, forge, speed) -- transport start/stop
		self.rolling = speed > 0 and true or false

		-- send note off event at transport stop with active note
		if not self.rolling and forge and active then
			forge:time(frames):midi(MIDI.NoteOff, active, vel)
			active = nil
		end
	end,
	[Time.barBeat] = function(self, frames, forge, barBeat)
		if self.rolling and forge and math.tointeger(barBeat) then
			-- send note off event for active note
			if active then
				forge:time(frames):midi(MIDI.NoteOff, active, vel)
				active = nil
			end

			-- get new note
			local note = notes[barBeat % #notes + 1]
			-- send note on event for new note
			if note then
				forge:time(frames):midi(MIDI.NoteOn, note, vel)
				active = note
			end
		end
	end
})

-- push time responder state and active note to stash
function stash(forge)
	local obj = forge:object()

	obj:key(Time.Position)
	timeR:stash(obj)

	if active then
		obj:key(urn.active):int(active)
	end

	obj:pop()
end

-- pop time responder state and active note from stash
function apply(atom)
	if atom[Time.Position] then
		timeR:apply(atom[Time.Position])
	end

	if atom[urn.active] then
		active = atom[urn.active].body
	end
end

function run(n, control, notify, seq, forge)
	local from = 0

	for to, atom in seq:foreach() do -- iterate over incoming events
		timeR(from, to, forge, atom) -- call responder for event

		from = to
	end

	timeR(from, n, forge)
end"""
	] .

1143 1144 1145 1146
moony:bank-template_part-1
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
1147
		moony:editorHidden false ;
1148
		moony:logHidden true ;
1149
		moony:logFollow true ;
1150
		moony:logReset false ;
1151 1152
		moony:paramHidden true ;
		moony:paramCols 3 ;
1153
		moony:paramRows 4 ;
1154 1155 1156 1157
		moony:code """-- Template 1: MIDI Responder

local block = false -- route unmatched messages as-is

1158
-- define a MIDIResponder object
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
local midiR = MIDIResponder({
	-- callbacks featuring a channel parameter
	[MIDI.NoteOn] = function(self, frames, forge, chan, note, vel)
		--TODO
	end,
	[MIDI.NoteOff] = function(self, frames, forge, chan, note, vel)
		--TODO
	end,
	[MIDI.NotePressure] = function(self, frames, forge, chan, note, vel)
		--TODO
	end,
	[MIDI.Bender] = function(self, frames, forge, chan, lsb, msb)
		--TODO
	end,
	[MIDI.Controller] = function(self, frames, forge, chan, cntrl, val)
		--TODO
	end,
	[MIDI.ProgramChange] = function(self, frames, forge, chan, lsb, msb)
		--TODO
	end,
	[MIDI.ChannelPressure] = function(self, frames, forge, chan, val)
		--TODO
	end,

	-- callbacks featuring no channel parameter
	[MIDI.SystemExclusive] = function(self, frames, forge, _, ...)
		--TODO
	end,
	[MIDI.QuarterFrame] = function(self, frames, forge, _, type, val)
		--TODO
	end,
	[MIDI.SongPosition] = function(self, frames, forge, _, lsb, msb) 
		--TODO
	end,
	[MIDI.SongSelect] = function(self, frames, forge, _, val)
		--TODO
	end,
	[MIDI.TuneRequest] = function(self, frames, forge)
		--TODO
	end,
	[MIDI.Clock] = function(self, frames, forge)
		--TODO
	end,
	[MIDI.Start] = function(self, frames, forge)
		--TODO
	end,
	[MIDI.Continue] = function(self, frames, forge)
		--TODO
	end,
	[MIDI.Stop] = function(self, frames, forge)
		--TODO
	end,
	[MIDI.ActiveSense] = function(self, frames, forge)
		--TODO
	end,
	[MIDI.Reset] = function(self, frames, forge)
		--TODO
	end
}, not block)

1219
function run(n, control, notify, seq, forge)
1220 1221 1222 1223 1224
	for frames, atom in seq:foreach() do -- iterate over incoming events
		local handled = midiR(frames, forge, atom) -- call responder for event
	end
end"""
	] .
1225 1226 1227 1228 1229

moony:bank-template_part-2
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
1230
		moony:editorHidden false ;
1231
		moony:logHidden true ;
1232
		moony:logFollow true ;
1233
		moony:logReset false ;
1234 1235
		moony:paramHidden true ;
		moony:paramCols 3 ;
1236
		moony:paramRows 4 ;
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
		moony:code """-- Template 2: Time Responder

-- define a TimeResponder object
local timeR = TimeResponder({
	[Time.speed] = function(self, frames, forge, speed)
		--TODO
	end,
	[Time.bar] = function(self, frames, forge, bar)
		--TODO
	end,
	[Time.barBeat] = function(self, frames, forge, barBeat)
		--TODO
	end,
	[Time.beatUnit] = function(self, frames, forge, beatUnit)
		--TODO
	end,
	[Time.beatsPerBar] = function(self, frames, forge, beatsPerBar)
		--TODO
	end,
	[Time.beatsPerMinute] = function(self, frames, forge, beatsPerMinute)
		--TODO
	end,
	[Time.framesPerSecond] = function(self, frames, forge, framesPerSecond)
		--TODO
	end,
	[Time.frame] = function(self, frames, forge, frame)
		--TODO
	end
})

1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
-- push time responder state to stash
function stash(forge)
	timeR:stash(forge)
end

-- pop time responder state from stash
function apply(atom)
	timeR:apply(atom)
end

1277
function run(n, control, notify, seq, forge)
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
	local from = 0 -- initial frame offset

	for to, atom in seq:foreach() do -- iterate over incoming events
		timeR(from, to, forge, atom) -- call responder for event

		from = to -- update to new frame offset
	end

	timeR(from, n, forge) -- call responder for remaining frames
end"""
	] .
1289 1290 1291 1292 1293

moony:bank-template_part-3
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
1294
		moony:editorHidden false ;
1295
		moony:logHidden true ;
1296
		moony:logFollow true ;
1297
		moony:logReset false ;
1298 1299
		moony:paramHidden true ;
		moony:paramCols 3 ;
1300
		moony:paramRows 4 ;
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
		moony:code """-- Template 3: OSC Responder

-- define an OSCResponder object
local oscR = OSCResponder({
	['/ping'] = function(self, frames, forge, fmt, ...)
		--TODO
	end,
	['/pong'] = function(self, frames, forge, fmt, ...)
		--TODO
	end
})

1313
function run(n, control, notify, seq, forge)
1314 1315 1316 1317 1318
	for frames, atom in seq:foreach() do -- iterate over incoming events
		local handled = oscR(frames, forge, atom) -- call responder for event
	end
end"""
	] .
1319 1320 1321 1322 1323

moony:bank-template_part-4
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
1324
		moony:editorHidden false ;
1325
		moony:logHidden true ;
1326
		moony:logFollow true ;
1327
		moony:logReset false ;
1328
		moony:paramHidden false ;
1329
		moony:paramCols 3 ;
1330
		moony:paramRows 4 ;
1331 1332 1333
		moony:code """-- Template 4: State Responder

-- define URI prefix for state parameters
1334
local urn = Mapper('urn:uuid:3473b33a-e6d2-471c-89d3-4dea1a0d8feb#')
1335 1336

-- define single parameter
1337
local param = Parameter({
1338 1339 1340
	[RDFS.label] = 'Awesome Parameter',
	[RDFS.comment] = 'does this and that...',
	[RDFS.range] = Atom.Int,
1341 1342
	[LV2.minimum] = 0,
	[LV2.maximum] = 10,
1343 1344
	[Units.unit] = Units.hz,
	[RDF.value] = 5
1345
})
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367

-- define a StateResponder object
local stateR = StateResponder({
	[Patch.readable] = {
		--TODO
	},
	[Patch.writable] = {
		[urn.param] = param -- register parameter to writable group
	}
})

-- push parameter values to disk
function save(forge)
	stateR:stash(forge)
end

-- pop parameter values from disk
function restore(atom)
	stateR:apply(atom)
end

-- register parameters to UI
1368
function once(n, control, notify)
1369 1370 1371
	stateR:register(0, notify)
end

1372 1373
function run(n, control, notify)
	for frames, atom in control:foreach() do -- iterate over incoming events
1374 1375 1376 1377
		local handled = stateR(frames, notify, atom)
	end
end"""
	] .
1378 1379 1380 1381 1382 1383 1384 1385

moony:bank-template_part-5
	a pset:Preset ;
	doap:license lic:Artistic-2.0 ;
	state:state [
		moony:editorHidden false ;
		moony:logHidden true ;
		moony:logFollow true ;
1386
		moony:logReset false ;
1387 1388 1389 1390 1391 1392
		moony:paramHidden false ;
		moony:paramCols 1 ;
		moony:paramRows 1 ;
		moony:code """-- Template 5: Code Injection

-- define URI prefix for state parameters
1393
local urn = Mapper('urn:uuid:1ad928a1-e050-4380-be39-8dca9bc18f44#')
1394 1395 1396 1397 1398 1399

-- pretty print error message from injection
local function perr(err)
  return string.gsub(err, '%b[]:', '')
end

1400 1401 1402 1403 1404 1405 1406 1407
-- define injection environment
local env = {}

-- define injection environment metatable
local mt = {
	__index = _ENV
}

1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
-- define injection parameter
local injection = Parameter({
  [RDFS.label] = 'Injection',
  [RDFS.comment] = 'enter your code for injection here',
  [RDFS.range] = Atom.String,
  [Moony.syntax] = Lua.lang,
  _value = '',
  [Patch.Get] = function(self)
    return self._value
  end,
  [Patch.Set] = function(self, value)
    self._value = value

1421 1422 1423
		env = {} -- create new environment
		setmetatable(env, mt)
    local fn, err = load(value, 'inj', 't', env) -- compile injection code
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462
    if fn then -- compilation succeded
      local stat, err = pcall(fn) -- run injection code
      if not stat then -- running code failed
        print(perr(err)) -- report error
      end
    else -- compilation failed
      print(perr(err)) -- report error
    end
  end
})

-- define a StateResponder object
local stateR = StateResponder({
  [Patch.writable] = {
    [urn.injection] = injection -- register parameter to writable group
  }
})

-- push parameter values to disk
function save(forge)
  stateR:stash(forge)
end

-- pop parameter values from disk
function restore(atom)
  stateR:apply(atom)
end

-- register parameters to UI
function once(n, control, notify)
  stateR:register(0, notify)
end

function run(n, control, notify)
  for frames, atom in control:foreach() do -- iterate over incoming events
    local handled = stateR(frames, notify, atom)
  end
end"""
	] .