musa-dsl 0.40.0 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/Gemfile +0 -1
- data/README.md +15 -1
- data/docs/README.md +1 -0
- data/docs/subsystems/datasets.md +75 -0
- data/docs/subsystems/generative.md +92 -6
- data/docs/subsystems/music.md +349 -19
- data/docs/subsystems/transport.md +26 -0
- data/lib/musa-dsl/datasets/dataset.rb +2 -0
- data/lib/musa-dsl/datasets/gdv.rb +3 -3
- data/lib/musa-dsl/datasets/p.rb +1 -1
- data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +4 -2
- data/lib/musa-dsl/datasets/score.rb +3 -1
- data/lib/musa-dsl/generative/darwin.rb +36 -1
- data/lib/musa-dsl/generative/generative-grammar.rb +31 -1
- data/lib/musa-dsl/generative/markov.rb +3 -1
- data/lib/musa-dsl/generative/rules.rb +54 -0
- data/lib/musa-dsl/generative/variatio.rb +69 -0
- data/lib/musa-dsl/midi/midi-recorder.rb +4 -0
- data/lib/musa-dsl/midi/midi-voices.rb +13 -1
- data/lib/musa-dsl/music/chord-definition.rb +7 -5
- data/lib/musa-dsl/music/chord-definitions.rb +37 -0
- data/lib/musa-dsl/music/chords.rb +88 -21
- data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +70 -521
- data/lib/musa-dsl/music/scale_kinds/bebop/bebop_dominant_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/bebop/bebop_major_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/bebop/bebop_minor_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/blues/blues_major_scale_kind.rb +100 -0
- data/lib/musa-dsl/music/scale_kinds/blues/blues_scale_kind.rb +99 -0
- data/lib/musa-dsl/music/scale_kinds/chromatic_scale_kind.rb +79 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/double_harmonic_scale_kind.rb +102 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/hungarian_minor_scale_kind.rb +102 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/neapolitan_major_scale_kind.rb +102 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/neapolitan_minor_scale_kind.rb +101 -0
- data/lib/musa-dsl/music/scale_kinds/ethnic/phrygian_dominant_scale_kind.rb +103 -0
- data/lib/musa-dsl/music/scale_kinds/harmonic_major/harmonic_major_scale_kind.rb +104 -0
- data/lib/musa-dsl/music/scale_kinds/major_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/altered_scale_kind.rb +106 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/dorian_b2_scale_kind.rb +104 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/locrian_sharp2_scale_kind.rb +103 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/lydian_augmented_scale_kind.rb +103 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/lydian_dominant_scale_kind.rb +106 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/melodic_minor_scale_kind.rb +104 -0
- data/lib/musa-dsl/music/scale_kinds/melodic_minor/mixolydian_b6_scale_kind.rb +103 -0
- data/lib/musa-dsl/music/scale_kinds/minor_harmonic_scale_kind.rb +125 -0
- data/lib/musa-dsl/music/scale_kinds/minor_natural_scale_kind.rb +123 -0
- data/lib/musa-dsl/music/scale_kinds/modes/dorian_scale_kind.rb +111 -0
- data/lib/musa-dsl/music/scale_kinds/modes/locrian_scale_kind.rb +114 -0
- data/lib/musa-dsl/music/scale_kinds/modes/lydian_scale_kind.rb +111 -0
- data/lib/musa-dsl/music/scale_kinds/modes/mixolydian_scale_kind.rb +111 -0
- data/lib/musa-dsl/music/scale_kinds/modes/phrygian_scale_kind.rb +111 -0
- data/lib/musa-dsl/music/scale_kinds/pentatonic/pentatonic_major_scale_kind.rb +93 -0
- data/lib/musa-dsl/music/scale_kinds/pentatonic/pentatonic_minor_scale_kind.rb +99 -0
- data/lib/musa-dsl/music/scale_kinds/symmetric/diminished_hw_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/symmetric/diminished_wh_scale_kind.rb +110 -0
- data/lib/musa-dsl/music/scale_kinds/symmetric/whole_tone_scale_kind.rb +99 -0
- data/lib/musa-dsl/music/scale_systems/equally_tempered_12_tone_scale_system.rb +80 -0
- data/lib/musa-dsl/music/scale_systems/twelve_semitones_scale_system.rb +60 -0
- data/lib/musa-dsl/music/scales.rb +606 -67
- data/lib/musa-dsl/musicxml/builder/note.rb +31 -92
- data/lib/musa-dsl/musicxml/builder/pitched-note.rb +33 -94
- data/lib/musa-dsl/musicxml/builder/rest.rb +30 -91
- data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +31 -91
- data/lib/musa-dsl/neumas/array-to-neumas.rb +1 -1
- data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +2 -2
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +367 -3
- data/lib/musa-dsl/series/base-series.rb +250 -240
- data/lib/musa-dsl/series/buffer-serie.rb +16 -5
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +29 -3
- data/lib/musa-dsl/series/main-serie-constructors.rb +19 -15
- data/lib/musa-dsl/series/main-serie-operations.rb +74 -29
- data/lib/musa-dsl/series/proxy-serie.rb +5 -1
- data/lib/musa-dsl/series/quantizer-serie.rb +16 -2
- data/lib/musa-dsl/series/queue-serie.rb +15 -1
- data/lib/musa-dsl/series/series-composer.rb +5 -2
- data/lib/musa-dsl/series/timed-serie.rb +8 -4
- data/lib/musa-dsl/transport/timer-clock.rb +4 -2
- data/lib/musa-dsl/transport/timer.rb +27 -4
- data/lib/musa-dsl/version.rb +1 -1
- data/musa-dsl.gemspec +18 -15
- metadata +85 -22
|
@@ -166,6 +166,8 @@ module Musa
|
|
|
166
166
|
#
|
|
167
167
|
# @param content [Object] element content
|
|
168
168
|
# @param attributes [Hash, nil] element attributes
|
|
169
|
+
#
|
|
170
|
+
# @return [void]
|
|
169
171
|
def initialize(content, attributes = nil)
|
|
170
172
|
@content = content
|
|
171
173
|
@attributes = attributes || {}
|
|
@@ -367,10 +369,12 @@ module Musa
|
|
|
367
369
|
# @param index [Integer] option index
|
|
368
370
|
#
|
|
369
371
|
# @return [Node] option converted to node
|
|
370
|
-
def
|
|
372
|
+
def get(index)
|
|
371
373
|
options[index].to_serie.to_node
|
|
372
374
|
end
|
|
373
375
|
|
|
376
|
+
alias_method :[], :get
|
|
377
|
+
|
|
374
378
|
# Converts options to series.
|
|
375
379
|
#
|
|
376
380
|
# Generates options and converts them to a {Musa::Series::Serie}.
|
|
@@ -406,6 +410,14 @@ module Musa
|
|
|
406
410
|
|
|
407
411
|
protected
|
|
408
412
|
|
|
413
|
+
# Generates condition block from simplified arguments.
|
|
414
|
+
#
|
|
415
|
+
# @param attribute [Symbol, nil] attribute to check
|
|
416
|
+
# @param after_collect_operation [Symbol, nil] operation on collected values
|
|
417
|
+
# @param comparison_method [Symbol, nil] comparison method to apply
|
|
418
|
+
# @param comparison_value [Object, nil] value to compare against
|
|
419
|
+
#
|
|
420
|
+
# @return [Proc, nil] condition block or nil if arguments incomplete
|
|
409
421
|
def generate_simple_condition_block(attribute = nil,
|
|
410
422
|
after_collect_operation = nil,
|
|
411
423
|
comparison_method = nil,
|
|
@@ -451,6 +463,9 @@ module Musa
|
|
|
451
463
|
|
|
452
464
|
# @param content [Object] node content
|
|
453
465
|
# @param attributes [Hash] node attributes
|
|
466
|
+
#
|
|
467
|
+
# @return [void]
|
|
468
|
+
#
|
|
454
469
|
# @api private
|
|
455
470
|
def initialize(content, attributes)
|
|
456
471
|
super()
|
|
@@ -482,6 +497,9 @@ module Musa
|
|
|
482
497
|
class BlockNode < Node
|
|
483
498
|
# @param attributes [Hash] node attributes
|
|
484
499
|
# @yield [parent, attributes] block to generate content
|
|
500
|
+
#
|
|
501
|
+
# @return [void]
|
|
502
|
+
#
|
|
485
503
|
# @api private
|
|
486
504
|
def initialize(attributes, &block)
|
|
487
505
|
@attributes = attributes
|
|
@@ -516,6 +534,9 @@ module Musa
|
|
|
516
534
|
class ConditionNode < Node
|
|
517
535
|
# @param node [Node] node to filter
|
|
518
536
|
# @yield [option] condition block
|
|
537
|
+
#
|
|
538
|
+
# @return [void]
|
|
539
|
+
#
|
|
519
540
|
# @api private
|
|
520
541
|
def initialize(node, &block)
|
|
521
542
|
@node = node
|
|
@@ -545,6 +566,9 @@ module Musa
|
|
|
545
566
|
class OrNode < Node
|
|
546
567
|
# @param node1 [Node] first alternative
|
|
547
568
|
# @param node2 [Node] second alternative
|
|
569
|
+
#
|
|
570
|
+
# @return [void]
|
|
571
|
+
#
|
|
548
572
|
# @api private
|
|
549
573
|
def initialize(node1, node2)
|
|
550
574
|
@node1 = node1
|
|
@@ -579,6 +603,9 @@ module Musa
|
|
|
579
603
|
class NextNode < Node
|
|
580
604
|
# @param node [Node] first node in sequence
|
|
581
605
|
# @param after [Node] node to follow
|
|
606
|
+
#
|
|
607
|
+
# @return [void]
|
|
608
|
+
#
|
|
582
609
|
# @api private
|
|
583
610
|
def initialize(node, after)
|
|
584
611
|
@node = node
|
|
@@ -609,6 +636,9 @@ module Musa
|
|
|
609
636
|
class RepeatNode < Node
|
|
610
637
|
# @param node [Node] node to repeat
|
|
611
638
|
# @param max [Integer, nil] maximum repetitions (nil = infinite)
|
|
639
|
+
#
|
|
640
|
+
# @return [void]
|
|
641
|
+
#
|
|
612
642
|
# @api private
|
|
613
643
|
def initialize(node, max = nil)
|
|
614
644
|
@node = node
|
|
@@ -97,7 +97,7 @@ module Musa
|
|
|
97
97
|
# Implements {Musa::Series::Serie} interface for integration with series operations.
|
|
98
98
|
class Markov
|
|
99
99
|
# TODO: adapt to series prototyping
|
|
100
|
-
include Musa::Series::Serie
|
|
100
|
+
include Musa::Series::Serie::Base
|
|
101
101
|
|
|
102
102
|
# Creates Markov chain generator.
|
|
103
103
|
#
|
|
@@ -113,6 +113,8 @@ module Musa
|
|
|
113
113
|
# start: :a,
|
|
114
114
|
# finish: :x
|
|
115
115
|
# )
|
|
116
|
+
#
|
|
117
|
+
# @return [void]
|
|
116
118
|
def initialize(transitions:, start:, finish: nil, random: nil)
|
|
117
119
|
@transitions = transitions.clone.freeze
|
|
118
120
|
|
|
@@ -149,6 +149,8 @@ module Musa
|
|
|
149
149
|
# cut 'validate' { |obj| prune if invalid?(obj) }
|
|
150
150
|
# ended_when { |obj| complete?(obj) }
|
|
151
151
|
# end
|
|
152
|
+
#
|
|
153
|
+
# @return [void]
|
|
152
154
|
def initialize(&block)
|
|
153
155
|
@dsl = RulesEvalContext.new(&block)
|
|
154
156
|
end
|
|
@@ -257,6 +259,7 @@ module Musa
|
|
|
257
259
|
# @return [Array<CutRule>] cut rules
|
|
258
260
|
attr_reader :_grow_rules, :_ended_when, :_cut_rules
|
|
259
261
|
|
|
262
|
+
# @return [void]
|
|
260
263
|
# @api private
|
|
261
264
|
def initialize(&block)
|
|
262
265
|
@_grow_rules = []
|
|
@@ -296,10 +299,24 @@ module Musa
|
|
|
296
299
|
self
|
|
297
300
|
end
|
|
298
301
|
|
|
302
|
+
# Checks if end condition is defined.
|
|
303
|
+
#
|
|
304
|
+
# @return [Boolean] true if ended_when was called
|
|
305
|
+
#
|
|
306
|
+
# @api private
|
|
299
307
|
def _has_ending?
|
|
300
308
|
!@_ended_when.nil?
|
|
301
309
|
end
|
|
302
310
|
|
|
311
|
+
# Evaluates end condition for object.
|
|
312
|
+
#
|
|
313
|
+
# @param object [Object] object to check
|
|
314
|
+
# @param history [Array] object history
|
|
315
|
+
# @param parameters [Hash] additional parameters
|
|
316
|
+
#
|
|
317
|
+
# @return [Boolean] true if object should end
|
|
318
|
+
#
|
|
319
|
+
# @api private
|
|
303
320
|
def _ended?(object, history, **parameters)
|
|
304
321
|
if @_ended_when
|
|
305
322
|
with object, history, **parameters, &@_ended_when
|
|
@@ -311,11 +328,21 @@ module Musa
|
|
|
311
328
|
class GrowRule
|
|
312
329
|
attr_reader :name
|
|
313
330
|
|
|
331
|
+
# @param name [String] rule name
|
|
332
|
+
#
|
|
333
|
+
# @return [void]
|
|
314
334
|
def initialize(name, &block)
|
|
315
335
|
@name = name
|
|
316
336
|
@block = block
|
|
317
337
|
end
|
|
318
338
|
|
|
339
|
+
# Generates possible branched objects.
|
|
340
|
+
#
|
|
341
|
+
# @param object [Object] object to branch
|
|
342
|
+
# @param history [Array] object history
|
|
343
|
+
# @param parameters [Hash] additional parameters
|
|
344
|
+
#
|
|
345
|
+
# @return [Array<Object>] branched objects
|
|
319
346
|
def generate_possibilities(object, history, **parameters)
|
|
320
347
|
# TODO: optimize context using only one instance for all genereate_possibilities calls
|
|
321
348
|
context = GrowRuleEvalContext.new
|
|
@@ -329,10 +356,16 @@ module Musa
|
|
|
329
356
|
|
|
330
357
|
attr_reader :_branches
|
|
331
358
|
|
|
359
|
+
# @return [void]
|
|
332
360
|
def initialize
|
|
333
361
|
@_branches = []
|
|
334
362
|
end
|
|
335
363
|
|
|
364
|
+
# Records a branched object.
|
|
365
|
+
#
|
|
366
|
+
# @param object [Object] branched object
|
|
367
|
+
#
|
|
368
|
+
# @return [self]
|
|
336
369
|
def branch(object)
|
|
337
370
|
@_branches << object
|
|
338
371
|
self
|
|
@@ -347,11 +380,21 @@ module Musa
|
|
|
347
380
|
class CutRule
|
|
348
381
|
attr_reader :reason
|
|
349
382
|
|
|
383
|
+
# @param reason [String] rejection reason
|
|
384
|
+
#
|
|
385
|
+
# @return [void]
|
|
350
386
|
def initialize(reason, &block)
|
|
351
387
|
@reason = reason
|
|
352
388
|
@block = block
|
|
353
389
|
end
|
|
354
390
|
|
|
391
|
+
# Checks if object should be rejected.
|
|
392
|
+
#
|
|
393
|
+
# @param object [Object] object to check
|
|
394
|
+
# @param history [Array] object history
|
|
395
|
+
# @param parameters [Hash] additional parameters
|
|
396
|
+
#
|
|
397
|
+
# @return [Array<String>, nil] rejection reasons or nil if not rejected
|
|
355
398
|
def rejects?(object, history, **parameters)
|
|
356
399
|
# TODO: optimize context using only one instance for all rejects? checks
|
|
357
400
|
context = CutRuleEvalContext.new
|
|
@@ -367,10 +410,16 @@ module Musa
|
|
|
367
410
|
|
|
368
411
|
attr_reader :_secondary_reasons
|
|
369
412
|
|
|
413
|
+
# @return [void]
|
|
370
414
|
def initialize
|
|
371
415
|
@_secondary_reasons = []
|
|
372
416
|
end
|
|
373
417
|
|
|
418
|
+
# Marks object for pruning.
|
|
419
|
+
#
|
|
420
|
+
# @param secondary_reason [String, nil] additional reason detail
|
|
421
|
+
#
|
|
422
|
+
# @return [self]
|
|
374
423
|
def prune(secondary_reason = nil)
|
|
375
424
|
@_secondary_reasons << secondary_reason
|
|
376
425
|
self
|
|
@@ -399,6 +448,11 @@ module Musa
|
|
|
399
448
|
class Node
|
|
400
449
|
attr_reader :parent, :children, :object, :rejected
|
|
401
450
|
|
|
451
|
+
# @param object [Object, nil] node object
|
|
452
|
+
# @param parent [Node, nil] parent node
|
|
453
|
+
#
|
|
454
|
+
# @return [void]
|
|
455
|
+
#
|
|
402
456
|
# @api private
|
|
403
457
|
def initialize(object = nil, parent = nil)
|
|
404
458
|
@parent = parent
|
|
@@ -143,6 +143,8 @@ module Musa
|
|
|
143
143
|
# field :y, [:a, :b]
|
|
144
144
|
# constructor { |x:, y:| { x: x, y: y } }
|
|
145
145
|
# end
|
|
146
|
+
#
|
|
147
|
+
# @return [void]
|
|
146
148
|
def initialize(instance_name, &block)
|
|
147
149
|
raise ArgumentError, 'instance_name should be a symbol' unless instance_name.is_a?(Symbol)
|
|
148
150
|
raise ArgumentError, 'block is needed' unless block
|
|
@@ -259,6 +261,11 @@ module Musa
|
|
|
259
261
|
|
|
260
262
|
private
|
|
261
263
|
|
|
264
|
+
# Generates evaluation tree for parameter calculation.
|
|
265
|
+
#
|
|
266
|
+
# @param fieldset [Fieldset] fieldset to process
|
|
267
|
+
#
|
|
268
|
+
# @return [A, nil] root node of evaluation tree
|
|
262
269
|
def generate_eval_tree_A(fieldset)
|
|
263
270
|
root = nil
|
|
264
271
|
current = nil
|
|
@@ -279,6 +286,11 @@ module Musa
|
|
|
279
286
|
root
|
|
280
287
|
end
|
|
281
288
|
|
|
289
|
+
# Generates evaluation tree for attribute application.
|
|
290
|
+
#
|
|
291
|
+
# @param fieldset [Fieldset] fieldset to process
|
|
292
|
+
#
|
|
293
|
+
# @return [B] root node of attribute tree
|
|
282
294
|
def generate_eval_tree_B(fieldset)
|
|
283
295
|
affected_field_names = []
|
|
284
296
|
inner = []
|
|
@@ -298,12 +310,19 @@ module Musa
|
|
|
298
310
|
attr_reader :parameter_name, :options
|
|
299
311
|
attr_accessor :inner
|
|
300
312
|
|
|
313
|
+
# @param parameter_name [Symbol] parameter name
|
|
314
|
+
# @param options [Array] option values
|
|
315
|
+
#
|
|
316
|
+
# @return [void]
|
|
301
317
|
def initialize(parameter_name, options)
|
|
302
318
|
@parameter_name = parameter_name
|
|
303
319
|
@options = options
|
|
304
320
|
@inner = nil
|
|
305
321
|
end
|
|
306
322
|
|
|
323
|
+
# Calculates all parameter combinations.
|
|
324
|
+
#
|
|
325
|
+
# @return [Array<Hash>] parameter combination hashes
|
|
307
326
|
def calc_parameters
|
|
308
327
|
unless @calc_parameters
|
|
309
328
|
if inner
|
|
@@ -320,16 +339,19 @@ module Musa
|
|
|
320
339
|
private_constant :A
|
|
321
340
|
|
|
322
341
|
class A1 < A
|
|
342
|
+
# @return [void]
|
|
323
343
|
def initialize(parameter_name, options)
|
|
324
344
|
super parameter_name, options
|
|
325
345
|
|
|
326
346
|
@own_parameters = @options.collect { |option| { @parameter_name => option } }
|
|
327
347
|
end
|
|
328
348
|
|
|
349
|
+
# @return [Array<Hash>] own parameter combinations
|
|
329
350
|
def calc_own_parameters
|
|
330
351
|
@own_parameters
|
|
331
352
|
end
|
|
332
353
|
|
|
354
|
+
# @return [String] string representation
|
|
333
355
|
def inspect
|
|
334
356
|
"A1 name: #{@parameter_name}, options: #{@options}, inner: #{@inner || 'nil'}"
|
|
335
357
|
end
|
|
@@ -340,6 +362,11 @@ module Musa
|
|
|
340
362
|
private_constant :A1
|
|
341
363
|
|
|
342
364
|
class A2 < A
|
|
365
|
+
# @param parameter_name [Symbol] parameter name
|
|
366
|
+
# @param options [Array] option values
|
|
367
|
+
# @param subcomponent [A] nested tree
|
|
368
|
+
#
|
|
369
|
+
# @return [void]
|
|
343
370
|
def initialize(parameter_name, options, subcomponent)
|
|
344
371
|
super parameter_name, options
|
|
345
372
|
|
|
@@ -361,10 +388,12 @@ module Musa
|
|
|
361
388
|
@own_parameters = result
|
|
362
389
|
end
|
|
363
390
|
|
|
391
|
+
# @return [Array<Hash>] own parameter combinations
|
|
364
392
|
def calc_own_parameters
|
|
365
393
|
@own_parameters
|
|
366
394
|
end
|
|
367
395
|
|
|
396
|
+
# @return [String] string representation
|
|
368
397
|
def inspect
|
|
369
398
|
"A2 name: #{@parameter_name}, options: #{@options}, subcomponent: #{@subcomponent}, inner: #{@inner || 'nil'}"
|
|
370
399
|
end
|
|
@@ -383,6 +412,13 @@ module Musa
|
|
|
383
412
|
class B
|
|
384
413
|
attr_reader :parameter_name, :options, :affected_field_names, :blocks, :inner
|
|
385
414
|
|
|
415
|
+
# @param parameter_name [Symbol] parameter name
|
|
416
|
+
# @param options [Array] option values
|
|
417
|
+
# @param affected_field_names [Array<Symbol>] field names affected
|
|
418
|
+
# @param inner [Array<B>] nested B nodes
|
|
419
|
+
# @param blocks [Array<Proc>] with_attributes blocks
|
|
420
|
+
#
|
|
421
|
+
# @return [void]
|
|
386
422
|
def initialize(parameter_name, options, affected_field_names, inner, blocks)
|
|
387
423
|
@parameter_name = parameter_name
|
|
388
424
|
@options = options
|
|
@@ -392,6 +428,12 @@ module Musa
|
|
|
392
428
|
@procedures = blocks.collect { |proc| Musa::Extension::SmartProcBinder::SmartProcBinder.new proc }
|
|
393
429
|
end
|
|
394
430
|
|
|
431
|
+
# Runs attribute application for this node.
|
|
432
|
+
#
|
|
433
|
+
# @param parameters_with_depth [Hash] parameters with nesting depth
|
|
434
|
+
# @param parent_parameters [Hash, nil] parent context parameters
|
|
435
|
+
#
|
|
436
|
+
# @return [void]
|
|
395
437
|
def run(parameters_with_depth, parent_parameters = nil)
|
|
396
438
|
parent_parameters ||= {}
|
|
397
439
|
|
|
@@ -417,6 +459,7 @@ module Musa
|
|
|
417
459
|
end
|
|
418
460
|
end
|
|
419
461
|
|
|
462
|
+
# @return [String] string representation
|
|
420
463
|
def inspect
|
|
421
464
|
"B name: #{@parameter_name}, options: #{@options}, affected_field_names: #{@affected_field_names}, blocks_size: #{@blocks.size}, inner: #{@inner}"
|
|
422
465
|
end
|
|
@@ -435,6 +478,10 @@ module Musa
|
|
|
435
478
|
# @return [Fieldset] defined fieldset
|
|
436
479
|
attr_reader :_fieldset
|
|
437
480
|
|
|
481
|
+
# @param name [Symbol] fieldset name
|
|
482
|
+
# @param options [Array, Range, nil] fieldset options
|
|
483
|
+
#
|
|
484
|
+
# @return [void]
|
|
438
485
|
# @api private
|
|
439
486
|
def initialize(name, options = nil, &block)
|
|
440
487
|
@_fieldset = Fieldset.new name, options.arrayfy.explode_ranges
|
|
@@ -446,6 +493,8 @@ module Musa
|
|
|
446
493
|
#
|
|
447
494
|
# @param name [Symbol] field name
|
|
448
495
|
# @param options [Array, Range, nil] field option values
|
|
496
|
+
#
|
|
497
|
+
# @return [void]
|
|
449
498
|
# @api private
|
|
450
499
|
def field(name, options = nil)
|
|
451
500
|
@_fieldset.components << Field.new(name, options.arrayfy.explode_ranges)
|
|
@@ -455,7 +504,10 @@ module Musa
|
|
|
455
504
|
#
|
|
456
505
|
# @param name [Symbol] fieldset name
|
|
457
506
|
# @param options [Array, Range, nil] fieldset option values
|
|
507
|
+
#
|
|
458
508
|
# @yield fieldset DSL block
|
|
509
|
+
#
|
|
510
|
+
# @return [void]
|
|
459
511
|
# @api private
|
|
460
512
|
def fieldset(name, options = nil, &block)
|
|
461
513
|
fieldset_context = FieldsetContext.new name, options, &block
|
|
@@ -465,6 +517,8 @@ module Musa
|
|
|
465
517
|
# Adds attribute modification block.
|
|
466
518
|
#
|
|
467
519
|
# @yield attribute modification block
|
|
520
|
+
#
|
|
521
|
+
# @return [void]
|
|
468
522
|
# @api private
|
|
469
523
|
def with_attributes(&block)
|
|
470
524
|
@_fieldset.with_attributes << block
|
|
@@ -481,6 +535,7 @@ module Musa
|
|
|
481
535
|
# @return [Proc, nil] finalize block
|
|
482
536
|
attr_reader :_constructor, :_finalize
|
|
483
537
|
|
|
538
|
+
# @return [void]
|
|
484
539
|
# @api private
|
|
485
540
|
def initialize(&block)
|
|
486
541
|
@_constructor = nil
|
|
@@ -492,6 +547,8 @@ module Musa
|
|
|
492
547
|
# Defines object constructor.
|
|
493
548
|
#
|
|
494
549
|
# @yield constructor block receiving field values
|
|
550
|
+
#
|
|
551
|
+
# @return [void]
|
|
495
552
|
# @api private
|
|
496
553
|
def constructor(&block)
|
|
497
554
|
@_constructor = block
|
|
@@ -500,6 +557,8 @@ module Musa
|
|
|
500
557
|
# Defines finalize block.
|
|
501
558
|
#
|
|
502
559
|
# @yield finalize block receiving completed object
|
|
560
|
+
#
|
|
561
|
+
# @return [void]
|
|
503
562
|
# @api private
|
|
504
563
|
def finalize(&block)
|
|
505
564
|
@_finalize = block
|
|
@@ -512,6 +571,7 @@ module Musa
|
|
|
512
571
|
attr_reader :name
|
|
513
572
|
attr_accessor :options
|
|
514
573
|
|
|
574
|
+
# @return [String] string representation
|
|
515
575
|
def inspect
|
|
516
576
|
"Field #{@name} options: #{@options}"
|
|
517
577
|
end
|
|
@@ -520,6 +580,10 @@ module Musa
|
|
|
520
580
|
|
|
521
581
|
private
|
|
522
582
|
|
|
583
|
+
# @param name [Symbol] field name
|
|
584
|
+
# @param options [Array] option values
|
|
585
|
+
#
|
|
586
|
+
# @return [void]
|
|
523
587
|
def initialize(name, options)
|
|
524
588
|
@name = name
|
|
525
589
|
@options = options
|
|
@@ -532,6 +596,7 @@ module Musa
|
|
|
532
596
|
attr_reader :name, :with_attributes, :components
|
|
533
597
|
attr_accessor :options
|
|
534
598
|
|
|
599
|
+
# @return [String] string representation
|
|
535
600
|
def inspect
|
|
536
601
|
"Fieldset #{@name} options: #{@options} components: #{@components}"
|
|
537
602
|
end
|
|
@@ -540,6 +605,10 @@ module Musa
|
|
|
540
605
|
|
|
541
606
|
private
|
|
542
607
|
|
|
608
|
+
# @param name [Symbol] fieldset name
|
|
609
|
+
# @param options [Array, nil] option values
|
|
610
|
+
#
|
|
611
|
+
# @return [void]
|
|
543
612
|
def initialize(name, options)
|
|
544
613
|
@name = name
|
|
545
614
|
@options = options || [nil]
|
|
@@ -79,6 +79,8 @@ module Musa
|
|
|
79
79
|
# @see https://github.com/javier-sy/midi-events MIDIEvents documentation
|
|
80
80
|
class MIDIRecorder
|
|
81
81
|
# @param sequencer [Musa::Sequencer::Sequencer] provides the musical position for each recorded message.
|
|
82
|
+
#
|
|
83
|
+
# @return [void]
|
|
82
84
|
def initialize(sequencer)
|
|
83
85
|
@sequencer = sequencer
|
|
84
86
|
@midi_parser = MIDIParser.new
|
|
@@ -179,6 +181,8 @@ module Musa
|
|
|
179
181
|
#
|
|
180
182
|
# @param position [Rational] sequencer position when captured.
|
|
181
183
|
# @param message [MIDIEvents::Event] parsed MIDI event.
|
|
184
|
+
#
|
|
185
|
+
# @return [void]
|
|
182
186
|
def initialize(position, message)
|
|
183
187
|
@position = position
|
|
184
188
|
@message = message
|
|
@@ -97,6 +97,8 @@ module Musa
|
|
|
97
97
|
# @param output [#puts, nil] anything responding to `puts` that accepts `MIDIEvents::Event`s (typically a MIDICommunications output).
|
|
98
98
|
# @param channels [Array<Numeric>, Range, Numeric] list of MIDI channels to control. Ranges are expanded automatically.
|
|
99
99
|
# @param do_log [Boolean] enables info level logs per emitted message.
|
|
100
|
+
#
|
|
101
|
+
# @return [void]
|
|
100
102
|
def initialize(sequencer:, output:, channels:, do_log: nil)
|
|
101
103
|
do_log ||= false
|
|
102
104
|
|
|
@@ -200,6 +202,8 @@ module Musa
|
|
|
200
202
|
# @param output [#puts, nil]
|
|
201
203
|
# @param channel [Integer] MIDI channel number (0-15).
|
|
202
204
|
# @param name [String, nil] human friendly identifier.
|
|
205
|
+
#
|
|
206
|
+
# @return [void]
|
|
203
207
|
def initialize(sequencer:, output:, channel:, name: nil, do_log: nil)
|
|
204
208
|
do_log ||= false
|
|
205
209
|
|
|
@@ -337,6 +341,8 @@ module Musa
|
|
|
337
341
|
class ControllersControl
|
|
338
342
|
# @param output [#puts] MIDI output.
|
|
339
343
|
# @param channel [Integer] MIDI channel number.
|
|
344
|
+
#
|
|
345
|
+
# @return [void]
|
|
340
346
|
def initialize(output, channel)
|
|
341
347
|
@output = output
|
|
342
348
|
@channel = channel
|
|
@@ -368,6 +374,8 @@ module Musa
|
|
|
368
374
|
#
|
|
369
375
|
# @param controller_number_or_symbol [Integer, Symbol] CC number or well-known alias (see +@controller_map+).
|
|
370
376
|
# @param value [Integer] byte value that will be clamped to 0-127.
|
|
377
|
+
#
|
|
378
|
+
# @return [Integer] clamped value
|
|
371
379
|
def []=(controller_number_or_symbol, value)
|
|
372
380
|
number = number_of(controller_number_or_symbol)
|
|
373
381
|
value ||= 0
|
|
@@ -377,10 +385,12 @@ module Musa
|
|
|
377
385
|
end
|
|
378
386
|
|
|
379
387
|
# @return [Integer, nil] last value assigned to the controller.
|
|
380
|
-
def
|
|
388
|
+
def get(controller_number_or_symbol)
|
|
381
389
|
@controller[number_of(controller_number_or_symbol)]
|
|
382
390
|
end
|
|
383
391
|
|
|
392
|
+
alias_method :[], :get
|
|
393
|
+
|
|
384
394
|
# Resolves a controller reference to its MIDI CC number.
|
|
385
395
|
#
|
|
386
396
|
# @param controller_number_or_symbol [Integer, Symbol] CC number or alias.
|
|
@@ -429,6 +439,8 @@ module Musa
|
|
|
429
439
|
# @param velocity [Numeric, Array<Numeric>] on velocity (can be per-note).
|
|
430
440
|
# @param duration [Numeric, nil] duration in bars or nil for infinite.
|
|
431
441
|
# @param velocity_off [Numeric, Array<Numeric>] release velocity.
|
|
442
|
+
#
|
|
443
|
+
# @return [void]
|
|
432
444
|
def initialize(voice, pitch:, velocity: nil, duration: nil, velocity_off: nil)
|
|
433
445
|
raise ArgumentError, "MIDIVoice: note duration should be nil or Numeric: #{duration} (#{duration.class})" unless duration.nil? || duration.is_a?(Numeric)
|
|
434
446
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'set'
|
|
2
|
-
|
|
3
1
|
module Musa
|
|
4
2
|
# Chord construction and manipulation framework.
|
|
5
3
|
#
|
|
@@ -115,10 +113,14 @@ module Musa
|
|
|
115
113
|
# @example
|
|
116
114
|
# ChordDefinition[:maj] # => <ChordDefinition :maj>
|
|
117
115
|
# ChordDefinition[:min7] # => <ChordDefinition :min7>
|
|
118
|
-
def self.
|
|
116
|
+
def self.get(name)
|
|
119
117
|
@definitions[name]
|
|
120
118
|
end
|
|
121
119
|
|
|
120
|
+
class << self
|
|
121
|
+
alias_method :[], :get
|
|
122
|
+
end
|
|
123
|
+
|
|
122
124
|
# Registers a new chord definition.
|
|
123
125
|
#
|
|
124
126
|
# Creates and registers a chord definition with specified intervals and features.
|
|
@@ -150,7 +152,7 @@ module Musa
|
|
|
150
152
|
definition.features.each { |k, v| @features_by_value[v] = k }
|
|
151
153
|
|
|
152
154
|
@feature_keys ||= Set[]
|
|
153
|
-
features.
|
|
155
|
+
features.each_key { |feature_name| @feature_keys << feature_name }
|
|
154
156
|
|
|
155
157
|
self
|
|
156
158
|
end
|
|
@@ -267,7 +269,7 @@ module Musa
|
|
|
267
269
|
|
|
268
270
|
# Checks if chord fits within a scale.
|
|
269
271
|
#
|
|
270
|
-
# @param scale [Scale] scale to check against
|
|
272
|
+
# @param scale [Scales::Scale] scale to check against
|
|
271
273
|
# @param chord_root_pitch [Integer] chord root pitch
|
|
272
274
|
# @return [Boolean] true if all chord notes are in scale
|
|
273
275
|
#
|
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
require_relative 'chord-definition'
|
|
2
2
|
|
|
3
|
+
# Standard chord definitions for Western harmony.
|
|
4
|
+
#
|
|
5
|
+
# This file registers the common chord types used in Western music theory,
|
|
6
|
+
# organized by size (number of notes) and quality (major, minor, etc.).
|
|
7
|
+
#
|
|
8
|
+
# ## Chord Categories
|
|
9
|
+
#
|
|
10
|
+
# ### Triads (3 notes)
|
|
11
|
+
# - **Major** (:maj) - Root, major 3rd, perfect 5th (0-4-7)
|
|
12
|
+
# - **Minor** (:min) - Root, minor 3rd, perfect 5th (0-3-7)
|
|
13
|
+
# - **Diminished** (:dim) - Root, minor 3rd, diminished 5th (0-3-6)
|
|
14
|
+
# - **Augmented** (:aug) - Root, major 3rd, augmented 5th (0-4-8)
|
|
15
|
+
#
|
|
16
|
+
# ### Seventh Chords (4 notes)
|
|
17
|
+
# - **Major 7th** (:maj7) - Major triad + major 7th (0-4-7-11)
|
|
18
|
+
# - **Minor 7th** (:min7) - Minor triad + minor 7th (0-3-7-10)
|
|
19
|
+
# - **Dominant 7th** (:dom7) - Major triad + minor 7th (0-4-7-10)
|
|
20
|
+
#
|
|
21
|
+
# ### Extended Chords (5+ notes)
|
|
22
|
+
# - **9th chords**: :maj9, :min9, :dom9
|
|
23
|
+
# - **11th chords**: :maj11, :min11
|
|
24
|
+
# - **13th chords**: :maj13, :min13
|
|
25
|
+
#
|
|
26
|
+
# ## Usage
|
|
27
|
+
#
|
|
28
|
+
# Chords are accessed via scale notes using the {Musa::Scales::NoteInScale#chord} method:
|
|
29
|
+
#
|
|
30
|
+
# scale = Scales.et12[440.0].major[60]
|
|
31
|
+
# scale.tonic.chord # Major triad (default)
|
|
32
|
+
# scale.tonic.chord :seventh # Major 7th
|
|
33
|
+
# scale.dominant.chord :seventh # Dominant 7th
|
|
34
|
+
# scale.tonic.chord quality: :minor # Minor triad
|
|
35
|
+
#
|
|
36
|
+
# @see Musa::Chords::ChordDefinition.register How chords are registered
|
|
37
|
+
# @see Musa::Chords::Chord How to build and use chords
|
|
38
|
+
# @see Musa::Scales::NoteInScale#chord Building chords from scale notes
|
|
39
|
+
|
|
3
40
|
# TODO trasladar los acordes de https://en.wikipedia.org/wiki/Chord_notation
|
|
4
41
|
|
|
5
42
|
# TRIADS
|