-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrhythm.rb
106 lines (92 loc) · 3.3 KB
/
rhythm.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
require_relative "utils"
module Polyphony
#
# Methods for generating rhythmic patterns.
#
module Rhythm
extend self
include Polyphony::Utils
include SonicPi::Lang::Core
# pure functions
#
# @param [Array<Integer>] pOffsets offsets
# @param [Integer] pNumUnits total number of units
#
# @return [Array<Integer>] spans based on offsets
#
def convertOffsetsToSpans(pOffsets, pNumUnits)
# @type [Array<Integer>]
offsets = pOffsets + [pNumUnits]
# @type [Array<Integer>]
spans = []
(offsets.length - 1).toRangeFromZero.each do |i|
spans.push(offsets[i + 1] - offsets[i])
end
return spans.freeze
end
#
# @param [Integer] pNumUnits total number of units
# @param [Float] pWeightForSpans weight affecting span value
#
# @return [Array<Integer>] rhythmic divisions of number of units
#
def divideUnitsRhythmically(pNumUnits, pWeightForSpans)
return 1 if (pNumUnits == 1)
# @type [Integer]
numRhythmicDivisions = chooseAbsIntWithWeight(-pWeightForSpans, (1..(pNumUnits / 2)).to_a)
# @type [Array<Integer>]
offsets = getTrueIndices(spread(numRhythmicDivisions, pNumUnits, rotate: rand_i(numRhythmicDivisions)))
# @type [Array<Integer>]
divisions = convertOffsetsToSpans(offsets, pNumUnits)
return divisions.freeze
end
#
# @param [Integer] pNumRhythms number of rhythms forming the polyrhythm
# @param [RangePairI] pRangeNumRhythmicDivisions range of rhythmic divisions
# @param [Integer] pNumUnitsPerMeasure number of units per measure
#
# @return [Array<Integer>] composite rhythm calculated from parameters
#
def getCompositeRhythm(pNumRhythms, pRangeNumRhythmicDivisions, pNumUnitsPerMeasure)
# @type [Array<Integer>]
compositeRhythm = []
pNumRhythms.times do
# @type [Integer]
numRhythmicDivisions = pRangeNumRhythmicDivisions.get
compositeRhythm = compositeRhythm.union(getTrueIndices(spread(numRhythmicDivisions, pNumUnitsPerMeasure, rotate: rand_i(numRhythmicDivisions))))
end
return compositeRhythm.sort.freeze
end
#
# @param [Array<Integer] pDivisions divisions
#
# @return [Array<Integer>] divisions whose first element is greater than 1, merged from the given
#
def mergeBriefStart(pDivisions)
unless (pDivisions.first == 1)
return pDivisions
else
# @type [Array<Integer>]
divisions = pDivisions.drop(1)
divisions[0] = (pDivisions[0] + pDivisions[1])
return divisions.freeze
end
end
#
# @param [Integer] pNumUnits total number of units
# @param [Float] pWeightForSpans weight affecting span value
#
# @return [Array<Integer>] rhythmic subdivisions of number of units
#
def subdivideUnitsRhythmically(pNumUnits, pWeightForSpans)
return 1 if (pNumUnits == 1)
# @type [Integer]
numRhythmicSubdivisions = chooseAbsIntWithWeight(-pWeightForSpans, (1..pNumUnits).to_a)
# @type [Array<Integer>]
offsets = getTrueIndices(spread(numRhythmicSubdivisions, pNumUnits, rotate: rand_i(numRhythmicSubdivisions)))
# @type [Array<Integer>]
subdivisions = convertOffsetsToSpans(offsets, pNumUnits)
return subdivisions.freeze
end
end
end