Module: MusicSetTheory::MusUtility

Included in:
MusicSetTheory, MusicSetTheory, NoteSeq, Temperament, Temperament
Defined in:
lib/music_set_theory/musutility.rb,
lib/music_set_theory/musutility.rb,
lib/music_set_theory/musutility.rb

Constant Summary collapse

SPACECOMMA =

Generates a unicode string from the items in seq delimited by commas. For example repseq([1, 2, 3]) produces "1, 2, 3". Arguments: seq: a sequence of items. pre_process: a function taking one argument and returning another. The function will execute this on each item in seq before concatenating them together. By default, nothing is done to each argument.

", "

Instance Method Summary collapse

Instance Method Details

#deep_freeze(obj) ⇒ Object



271
272
273
# File 'lib/music_set_theory/musutility.rb', line 271

def deep_freeze( obj )
  IceNine.deep_freeze(obj)
end

#deep_melt(obj) ⇒ Object



275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/music_set_theory/musutility.rb', line 275

def deep_melt( obj )
  case obj
  when Hash
    obj.each_with_object({}) do |(key, value), new_hash|
      new_hash[deep_melt(key)] = deep_melt(value)
    end
  when Array
    obj.map { |element| deep_melt(element) }
  when Object
    # インスタンス変数の解除
    obj.instance_variables.each do |var|
      deep_melt(var)
      value = obj.instance_variable_get(var)
      obj.remove_instance_variable(var)
      obj.instance_variable_set(var, deep_melt(value))
    end
    obj.dup rescue obj # 凍結状態を解除
  else
    obj.dup rescue obj
  end
  obj.dup rescue obj
end

#enl_seq(seq_of_seq, otherentries) ⇒ Object

Returns a sequence of sequences, with each element consisting of an element from otherentries appended to a sequence from seq_of_seq.

Note: this is used for building chords.



223
224
225
226
227
228
229
230
231
# File 'lib/music_set_theory/musutility.rb', line 223

def enl_seq( seq_of_seq, otherentries )
  ret = []
  for i in seq_of_seq
     for j in otherentries
         ret.append(i + [j])
     end
  end
  ret
end

#multislice(seq, slice, mod: 0, offset: 0) ⇒ Object

The multislice function takes a multiple-element-slice (see below) of a sequence, rotates it if necessary afterward, and returns it. The arguments:

Args

seq

a sequence to slice and/or rotate.

slice

another sequence which specifies the elements preserved in seq. This consists of integers, which indicate the indices of elements in seq to preserve. If i is in slice, then seq is preserved; otherwise, it is discarded. (Slicing always happens before rotation).

mod

if present, then all indices in slice are taken modulo this number. I.e., seq is preserved if and only if j some k modulo mod, where k is in slice.

offset

after slicing, this sequence is rotated this number of places.

def multislice( seq, slice, mod = 0, offset = 0 )



183
184
185
186
187
188
189
190
191
# File 'lib/music_set_theory/musutility.rb', line 183

def multislice( seq, slice, mod: 0, offset: 0 )
  ret = nil
  if 0 == mod
    ret = slice.map{|index| rotate(seq, offset)[index] }
  else
    ret = slice.map{|index| rotate(seq, offset)[index % mod] }
  end
  ret
end

#norm_seq(seq, mod) ⇒ Object

This function takes a sequence (of numbers) and "normalizes" it. To be specific, it evaluates all numbers inside seq modulo mod. The result is then sorted, and any duplicates are removed.

Note: this function is useful for looking up chords by their patterns.



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/music_set_theory/musutility.rb', line 240

def norm_seq( seq, mod )

  #sorted_seq = sorted([x % mod for x in seq])
  sorted_seq = seq.map{|x| x % mod }.sort

  # We remove duplicates. The following code is straight outta the Python FAQ.

  #
  last = sorted_seq[-1]
  # for i in range(len(sorted_seq)-2, -1, -1)
  (sorted_seq.size-2).step(0, -1) do |i|
    if last == sorted_seq[i]
      # del sorted_seq[i]
      sorted_seq.delete_at(i)
    else
      last = sorted_seq[i]
    end
  end

  sorted_seq
end

#repseq(seq, pre_process = lambda{|x| x}) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/music_set_theory/musutility.rb', line 202

def repseq( seq, pre_process = lambda{|x| x} )
  if seq.size == 0
    return ""
  end
  #str_out = ''.join([(str(pre_process(item)) + SPACECOMMA)
  #  for item in seq[:-1]]) + str(pre_process(seq[-1]));

  # ret = (seq[0...-1].map{|item| pre_process.(item).to_s }.join(SPACECOMMA)) +
  #       + SPACECOMMA + pre_process.(seq[-1]).to_s
  ret = (seq[0...-1].map{|item| pre_process.(item).to_s } +
         [pre_process.(seq[-1]).to_s]).join(SPACECOMMA)

  ret
end

#rotate(seq, offset) ⇒ Object

Original comments: Rotates a seq to the left by offset places; the elements shifted off are inserted back at the end. By setting offset to the negative number -N, this function rotates the sequence N places.

Note: this algorithm is a modification of one originally provided by Thorsten Kampe; this version handles zero sequences and right shifts. See: http://bytes.com/topic/python/answers/36070-rotating-lists



110
111
112
# File 'lib/music_set_theory/musutility.rb', line 110

def rotate( seq, offset )
  seq.rotate(offset)
end

#rotate_and_zero(seq, offset, mod = 0, debug_f: false) ⇒ Object

Original comments: Returns the result of:

(a) rotating a sequence to a given offset; and then,
(b) scalar subtracting the resulting first element from the rotated
  sequence.

The result always begins with zero (except when seq is []). If mod is not 0, then all subtraction occurs modulo mod.

Note: this function is useful in generating different modes of a scale and different synonyms of a chord.



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/music_set_theory/musutility.rb', line 153

def rotate_and_zero( seq, offset, mod = 0, debug_f: false )
  return seq if seq.empty?

  rotated_seq = rotate(seq, offset)
  first_elem  = rotated_seq[0]
  $stderr.puts "{#{__method__}} seq: #{seq}, offset: #{offset}" if debug_f
  $stderr.puts "{#{__method__}} rotated: #{rotated_seq}," +
    " 1st: #{first_elem.inspect}" if debug_f

  return scalar_addition(rotated_seq, 0 - first_elem, mod)
end

#scalar_addition(seq, scalar, mod = 0) ⇒ Object

Original comments: Returns the result of adding scalar (a number) to all elements in seq. If mod is not 0, then all addition occurs modulo mod.

Note: this function is an "analogue" of scalar multiplication - an operation where every element in a sequence is multiplied by a scalar. We can also use this function to perform "scalar subtraction" - the subtraction of a scalar from all elements in a sequence. """



130
131
132
133
134
135
136
137
138
# File 'lib/music_set_theory/musutility.rb', line 130

def scalar_addition( seq, scalar, mod = 0 )
  seq.map{|index|
    if 0 == mod
      index + scalar
    else
      (index + scalar) % mod
    end
  }
end

#seqtostr(value) ⇒ Object

Make sequences representable as strings.

Writes a sequence as a comma delimited string.



78
79
80
81
82
# File 'lib/music_set_theory/musutility.rb', line 78

def seqtostr( value )
  ary = value
  ary = ary.to_a unless ary.is_a? Array
  ary.join(", ")
end