zgomot 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -164,6 +164,22 @@ Percussion supports the following transformations,
164
164
 
165
165
  * <tt>bpm!(bpm)</tt>: change the bits per minute at which the note is played.
166
166
 
167
+ == Note List
168
+
169
+ A Note List is a set of notes or percussive notes that start playing simultaneously. The Note List may contain any number of notes and its duration is the duration of the longest note in the list. It is defined by,
170
+
171
+ nl(n1, n2, ..., nN)
172
+
173
+ where <tt>nN</tt> is the <tt>N'th</tt> note in the list.
174
+
175
+ ==== Transforms
176
+
177
+ * <tt>shift</tt>: Remove and return the first note from the progression.
178
+ * <tt>unshift</tt>: Add a note to the beginning of the progression.
179
+ * <tt>pop</tt>: Remove and return the last note from the progression.
180
+ * <tt>push</tt>: Add a note to the end of the progression.
181
+ * <tt>reverse!</tt>: Reverse the notes in the progression.
182
+
167
183
  == Chord Progressions
168
184
 
169
185
  Chord Progressions or Roman Numeral Notation permit the definition of a melody that is independent of key. Using Chord progressions it is possible to iteratively shift the key of a specified sequence of chords.
@@ -188,15 +204,18 @@ A chord progression in a key of F# dorian at octave 5 with notes of half note le
188
204
  * <tt>tonic!(tonic)</tt>: Change the tonic pitch of the progression.
189
205
  * <tt>mode!(mode)</tt>: Change the mode of the progression
190
206
  * <tt>[](*args)</tt>: By default when a progression is created it only consists of one each of the notes in the key played sequentially. Using this transformation it is possible to change the the notes played in the progression. For example <tt>cp([:Fs, 5], :dorian)[1,5,5,7]</tt> will play the sequence <tt>1, 5, 5, 7</tt> instead of <tt>1, 2, 3, 4, 5, 6, 7</tt>.
191
- * <tt>velocity=(v)</tt>: Change the velocity of all notes in the progression.
192
- * <tt>length=(v)</tt>: Change the length of all notes in the progression.
207
+ * <tt>velocity!(v)</tt>: Change the velocity of all notes in the progression.
208
+ * <tt>length!(v)</tt>: Change the length of all notes in the progression.
193
209
  * <tt>bpm!(bpm)</tt>: change the bits per minute at which the chord is played.
194
210
  * <tt>octave!(ocatve)</tt>: change the octave of all notes in the progression.
195
211
  * <tt>arp!(length)</tt>: arpeggiate the chords in the progression using the specified length in units of note length. Accepted values are 1, 2, 4, 8, ... resolution, representing arpeggiation by a whole note, half note, quarter note, eighth note up to the specified clock resolution.
196
212
  * <tt>inv!(number)</tt>: The inversion number. A value of zero will leave the chord unchanged, 1 is the first inversion and 2 is the second. Higher inversions just shift the chord to a higher octave.
197
213
  * <tt>rev!</tt>: Reverse the order in which the notes are played. Only noticeable if the chords in the progression are also arpeggiated.
198
-
199
- Progressions internally are arrays of notes. The following array methods are supported: <tt>reverse!, shift, pop, push, unshift</tt>
214
+ * <tt>shift</tt>: Remove and return the first chord from the progression.
215
+ * <tt>unshift</tt>: Add a chord to the beginning of the progression.
216
+ * <tt>pop</tt>: Remove and return the last chord from the progression.
217
+ * <tt>push</tt>: Add a chord to the end of the progression.
218
+ * <tt>reverse!</tt>: Reverse the chords in the progression.
200
219
 
201
220
  == Note Progressions
202
221
 
@@ -220,12 +239,15 @@ An note progression in a key of F# dorian at octave 5 with notes of half note le
220
239
  * <tt>tonic!(tonic)</tt>: Change the tonic pitch of the progression.
221
240
  * <tt>mode!(mode)</tt>: Change the mode of the progression
222
241
  * <tt>[](*args)</tt>: By default when a progression is created it only consists of one each of the notes in the key played sequentially using this transformation it is possible to change the the notes played in the progression. For example <tt>np([:Fs, 5], :dorian)[1,5,5,7]</tt> will play the sequence 1, 5, 5, 7 instead of 1, 2, 3, 4, 5, 6, 7.
223
- * <tt>velocity=(v)</tt>: Change the velocity of all notes in the progression.
224
- * <tt>length=(v)</tt>: Change the length of all notes in the progression.
225
- * <tt>bpm!(bpm)</tt>: change the bits per minute at which the chord is played.
226
- * <tt>octave!(ocatve)</tt>: change the octave of all notes in the progression.
227
-
228
- Progressions internally are arrays of notes. The following array methods are supported: <tt>reverse!, shift, pop, push, unshift</tt>
242
+ * <tt>velocity!(v)</tt>: Change the velocity of all notes in the progression.
243
+ * <tt>length!(v)</tt>: Change the length of all notes in the progression.
244
+ * <tt>bpm!(bpm)</tt>: Change the bits per minute at which the chord is played.
245
+ * <tt>octave!(ocatve)</tt>: Change the octave of all notes in the progression.
246
+ * <tt>shift</tt>: Remove and return the first note from the progression.
247
+ * <tt>unshift</tt>: Add a note to the beginning of the progression.
248
+ * <tt>pop</tt>: Remove and return the last note from the progression.
249
+ * <tt>push</tt>: Add a note to the end of the progression.
250
+ * <tt>reverse!</tt>: Reverse the notes in the progression.
229
251
 
230
252
  == Progression with Defined Length and Velocity by Note
231
253
 
@@ -237,6 +259,12 @@ Different durations and velocities for each note in a progression can be defined
237
259
 
238
260
  Patterns are heterogeneous arrays of notes, chords, Chord Progressions and Note Progressions. Operations applied to the pattern will be delegated to the appropriate elements of the pattern array.
239
261
 
262
+ Also, custom transformations can be applied to the items of a pattern using <tt>map</tt>,
263
+
264
+ pattern.map do |item|
265
+ transform(item)
266
+ end
267
+
240
268
  == Streams
241
269
 
242
270
  A stream is used to define iteration on a pattern and outputs a stream of MIDI data.
@@ -357,13 +385,21 @@ where <tt>name</tt> is the name of the <tt>input</tt>. There can be only one MID
357
385
 
358
386
  MIDI CC messages can be used to assign values to variables that can be read by programs. To assign a CC message to a variable use,
359
387
 
360
- add_cc(name, ch, options)
388
+ add_cc(name, cc, options)
361
389
 
362
- Where <tt>name</tt> is the variable name, ,<tt>ch</tt> is the MIDI CC identifier, a number between 0 and 255 and options are the following,
390
+ Where <tt>name</tt> is the variable name, ,<tt>cc</tt> is the MIDI CC identifier, a number between 0 and 255 and options are the following,
363
391
 
364
392
  * <tt>:max</tt>: The maximum value of the CC message. The default is 1.
365
393
  * <tt>:min</tt>: The minimum value of the CC message. The default is 0.
394
+ * <tt>:channel</tt>: The CC channel number. The default is 1.
366
395
  * <tt>:type</tt>: The CC message type. Accepted values are <tt>:cont</tt> and <tt>:switch</tt>. <tt>:cont</tt> type varies continuously between <tt>:max</tt> and <tt>:min</tt>. <tt>:switch</tt> type is boolean.
396
+ * <tt>:init</tt>: The initial value of the CC message. The default is 0 if type is <tt>:cont</tt> and <tt>false</tt> if type is <tt>:switch</tt>.
397
+
398
+ A block can also be passed to <tt>add_cc</tt> which is yielded the updated cc parameters. For example a CC which pauses a stream would look like,
399
+
400
+ add_cc('pause', 17, :type => :switch) do
401
+ pause('my_stream')
402
+ end
367
403
 
368
404
  To read a variable assigned to a CC message use,
369
405
 
@@ -391,7 +427,7 @@ All commands and objects described previously are available and can be typed dir
391
427
  * <tt>pause name</tt>: Pause the named stream. If no name is given pause all <tt>playing</tt> streams.
392
428
  * <tt>stop name</tt>: An alias for <tt>pause</tt>.
393
429
  * <tt>tog name</tt>: Toggle the status of the named stream. <tt>name</tt> is required.
394
-
430
+ * <tt>watch dir</tt>: Automatically load any new or updated files in <tt>dir</tt>. The default value of <tt>dir</tt> is the current directory.
395
431
 
396
432
  === Dashboard
397
433
 
@@ -401,7 +437,9 @@ and defined CCs. The time, stream and CC status are updated every beat. Also, st
401
437
  * <tt>q</tt>: Quit <tt>dash</tt>.
402
438
  * <tt>p</tt>: Play all streams.
403
439
  * <tt>s</tt>: Stop all streams.
404
- * <tt>t</tt>: Toggle the <tt>playing/paused</tt> status of a stream. When <tt>t</tt> is entered use the up/down keys to traverse the list of streams and type return to select a stream. Type <tt>t</tt> again to exit without selecting a stream.
440
+ * <tt>t</tt>: Toggle the <tt>playing/paused</tt> status of selected streams. When <tt>t</tt> is entered use the <tt>up/down</tt> keys to traverse the list of streams and type <tt>return</tt> to select a stream. Multiple streams can be selected. Type <tt>t</tt> again to toggle the status of the selected streams.
441
+ * <tt>d</tt>: Delete selected streams. When <tt>d</tt> is entered use the <tt>up/down</tt> keys to traverse the list of streams and type <tt>return</tt> to select a stream. Multiple streams can be selected. Type <tt>d</tt> again to delete the selected streams.
442
+
405
443
 
406
444
  == Callbacks
407
445
 
data/Rakefile CHANGED
@@ -18,6 +18,7 @@ require 'jeweler'
18
18
  gem.add_dependency('ffi', '~> 1.0.9')
19
19
  gem.add_dependency('rainbow', '~> 1.1.4')
20
20
  gem.add_dependency('pry', '~> 0.9.12.2')
21
+ gem.add_dependency('fssm', '~> 0.2.10')
21
22
  end
22
23
  rescue LoadError
23
24
  abort "jeweler is not available. In order to run test, you must: sudo gem install technicalpickles-jeweler --source=http://gems.github.com"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.2
1
+ 1.0.3
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require "#{File.dirname(__FILE__)}/../lib/zgomot"
3
+
4
+ before_start do
5
+ Zgomot.logger.level = Logger::DEBUG
6
+ end
7
+
8
+ str 'cycle', np([:Fs, 4], :dorian, :l=>4)[3,1,3,5] do |pattern|
9
+ pattern.push(pattern.shift.first)
10
+ end
11
+
12
+ play
13
+
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require "#{File.dirname(__FILE__)}/../lib/zgomot"
3
+
4
+ before_start do
5
+ Zgomot.logger.level = Logger::DEBUG
6
+ end
7
+
8
+ str 'cycle', [nl(n([:C,5]), n(:B)), nl(n(:G), n(:C,))] do |pattern|
9
+ notes = pattern.shift
10
+ pattern.map{|n| n.push(notes.shift)}
11
+ end
12
+
13
+ play
14
+
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require "#{File.dirname(__FILE__)}/../lib/zgomot"
3
+
4
+ before_start do
5
+ Zgomot.logger.level = Logger::DEBUG
6
+ end
7
+
8
+ if sources.include?("nanoKONTROL")
9
+ add_input("nanoKONTROL")
10
+ add_cc(:mult, 33, :type => :cont, :min => 0, :max => 3, :init => 0)
11
+ len = 4
12
+ str 'dynamic', np([:A,4],2,:l=>len)[7,5,3,1] do |pattern|
13
+ pattern.length!((2**cc(:mult).to_i)*len)
14
+ end
15
+ play
16
+ end
17
+
18
+
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require "#{File.dirname(__FILE__)}/../lib/zgomot"
3
+
4
+ before_start do
5
+ Zgomot.logger.level = Logger::DEBUG
6
+ end
7
+
8
+ if sources.include?("nanoKONTROL")
9
+ add_input("nanoKONTROL")
10
+ add_cc(:mult, 33, :type => :cont, :min => 0, :max => 4, :init => 0)
11
+ len = 4
12
+ str 'perc', [pr(:low_floor_tom, :l => len),
13
+ pr(:low_tom, :l => len),
14
+ n(:R, :l=> len),
15
+ pr(:high_mid_tom, :l => len)], :ch=>0 do |pattern|
16
+ pattern.length!((2**cc(:mult).to_i)*len)
17
+ end
18
+ play
19
+ end
20
+
21
+
22
+
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require "#{File.dirname(__FILE__)}/../lib/zgomot"
3
+
4
+ before_start do
5
+ Zgomot.logger.level = Logger::DEBUG
6
+ end
7
+
8
+ if sources.include?("GECO")
9
+ add_input("GECO")
10
+ add_cc(:mode, 17, :type => :cont, :min => 0, :max => 6, :init => 0)
11
+ str 'simple_input', np([:A,4],2,:l=>4)[7,5,3,1] do |pattern|
12
+ pattern.mode!(cc(:mode).to_i)
13
+ end
14
+ play
15
+ end
16
+
@@ -9,11 +9,15 @@ if sources.include?("nanoKONTROL")
9
9
  add_input("nanoKONTROL")
10
10
  add_cc(:mode, 17, :type => :cont, :min => 0, :max => 6, :init => 0)
11
11
  add_cc(:reverse, 13, :type => :switch)
12
+ add_cc(:turn_off, 12, :type => :switch)
13
+ add_cc(:turn_off, 12, :type => :switch) do
14
+ tog(:simple_input)
15
+ end
12
16
  str 'simple_input', np([:A,4],2,:l=>4)[7,5,3,1] do |pattern|
13
17
  if cc(:reverse)
14
- pattern.mode!(cc(:mode).to_i).reverse!
18
+ pattern.mode!(mode.to_i).reverse!
15
19
  else
16
- pattern.mode!(cc(:mode).to_i)
20
+ pattern.mode!(mode.to_i)
17
21
  end
18
22
  end
19
23
  play
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require "#{File.dirname(__FILE__)}/../lib/zgomot"
3
+
4
+ before_start do
5
+ Zgomot.logger.level = Logger::DEBUG
6
+ end
7
+
8
+ str 'notes' do
9
+ [nl(n([:C,5]), n(:B)), nl(n(:G), n(:C,))]
10
+ end
11
+
12
+ play
@@ -1,11 +1,15 @@
1
1
  set_config(:beats_per_minute=>120, :time_signature=>"4/4", :resolution=>"1/64")
2
2
 
3
- add_input("nanoKONTROL") if sources.include?("nanoKONTROL")
3
+ if sources.include?("nanoKONTROL")
4
+ add_input("nanoKONTROL")
5
+ end
4
6
  add_cc(:mode, 17, :type => :cont, :min => 0, :max => 6, :init => 0)
5
7
  add_cc(:reverse, 13, :type => :switch)
8
+ add_cc(:toggle_input, 12, :type => :switch) do
9
+ tog(:input)
10
+ end
6
11
 
7
-
8
- str 'input', np([:A,4],2,:l=>4)[7,5,3,1], :ch=>0 do |pattern|
12
+ str 'input', np([:A,4],6,:l=>4)[1,3,7,2], :ch=>0 do |pattern|
9
13
  if cc(:reverse)
10
14
  pattern.mode!(cc(:mode).to_i).reverse!
11
15
  else
@@ -9,6 +9,7 @@ require 'monitor'
9
9
  require 'ffi'
10
10
  require 'rainbow'
11
11
  require 'curses'
12
+ require 'fssm'
12
13
 
13
14
  require 'zgomot/config'
14
15
  require 'zgomot/boot'
@@ -1,3 +1,5 @@
1
+ Thread.abort_on_exception = true
2
+
1
3
  module Zgomot
2
4
 
3
5
  class Boot
@@ -7,5 +7,6 @@ require 'zgomot/comp/perc'
7
7
  require 'zgomot/comp/progression'
8
8
  require 'zgomot/comp/pitch_class'
9
9
  require 'zgomot/comp/markov'
10
+ require 'zgomot/comp/note_list'
10
11
 
11
12
 
@@ -36,8 +36,8 @@ module Zgomot::Comp
36
36
  attr_reader :chord_intervals
37
37
  end
38
38
 
39
- attr_reader :tonic, :chord, :clock, :intervals, :arp, :time_scale, :items, :inversion, :reverse
40
- attr_accessor :length, :velocity
39
+ attr_reader :tonic, :chord, :clock, :intervals, :arp, :time_scale, :items, :inversion, :reverse,
40
+ :length, :velocity
41
41
 
42
42
  def initialize(args)
43
43
  @length, @velocity, @chord = args[:length], args[:velocity], args[:chord]
@@ -82,6 +82,12 @@ module Zgomot::Comp
82
82
  def octave!(v)
83
83
  @notes = nil; @octave = v; self
84
84
  end
85
+ def length!(v)
86
+ @length = v; self
87
+ end
88
+ def valocity!(v)
89
+ @length = v; self
90
+ end
85
91
  def length_to_sec
86
92
  time_scale*Zgomot::Midi::Clock.whole_note_sec*(1.0/length + (arp.to_f.eql?(0.0) ? 0.0 : intervals.length.to_f/arp.to_f))
87
93
  end
@@ -19,7 +19,7 @@ module Zgomot::Comp
19
19
  def initialize(mode = 1)
20
20
  @mode = case mode
21
21
  when Symbol then self.class.modes.index(mode)+1
22
- when Fixnum then mode
22
+ when Fixnum then mode % 7
23
23
  when nil then 1
24
24
  else raise(Zgomot::Error, "#{mode.inspect} is invalid mode")
25
25
  end
@@ -0,0 +1,68 @@
1
+ module Zgomot::Comp
2
+
3
+ class NoteList
4
+
5
+ def self.nl(*args)
6
+ NoteList.new(*args)
7
+ end
8
+
9
+ attr_reader :notes, :clock
10
+
11
+ def initialize(*notes)
12
+ unless notes.all?{|n| n.class == Zgomot::Midi::Note or n.class == Zgomot::Comp::Perc}
13
+ raise(Zgomot::Error, "all arguments must be class Zgomot::Midi::Note Zgomot::Comp::Perc")
14
+ end
15
+ @notes = notes
16
+ end
17
+ def <<(note)
18
+ notes << note
19
+ end
20
+ def length_to_sec
21
+ notes.map(&:length_to_sec).max
22
+ end
23
+ def to_midi
24
+ notes.map{|n| n.to_midi}
25
+ end
26
+ def channel=(chan)
27
+ notes.each{|n| n.channel = chan}
28
+ end
29
+ def offset=(time)
30
+ notes.each{|n| n.offset = time}
31
+ end
32
+ def velocity!(v)
33
+ notes.each{|n| n.velocity!(v)}; self
34
+ end
35
+ def length!(v)
36
+ notes.each{|n| n.length!(v)}; self
37
+ end
38
+ def bpm!(bpm)
39
+ notes.each{|n| n.bpm!(bpm)}; self
40
+ end
41
+ def octave!(oct)
42
+ notes.each{|n| n.octave!(oct)}; self
43
+ end
44
+ def shift
45
+ @notes.shift
46
+ end
47
+ def unshift(n)
48
+ @notes.unshift(n); self
49
+ end
50
+ def pop
51
+ @notes.pop
52
+ end
53
+ def push(n)
54
+ @notes.push(n); self
55
+ end
56
+ def reverse!
57
+ @notes.reverse!; self
58
+ end
59
+ def time=(time)
60
+ @clock = Zgomot::Midi::Clock.new
61
+ clock.update(time)
62
+ notes.each{|n| n.time = clock.current_time}
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
@@ -21,9 +21,9 @@ module Zgomot::Comp
21
21
  Progression.new(:item => Chord::Progression.new(:scale), :tonic => tonic, :mode => mode, :length => l, :velocity => v)
22
22
  end
23
23
 
24
- def pr(percs = acoustic_bass_drum, opts = {})
24
+ def pr(perc = :acoustic_bass_drum, opts = {})
25
25
  l = opts[:l] || 4; v = opts[:v] || 0.6
26
- Perc.new(:percs => percs, :length => l, :velocity => v)
26
+ Perc.new(:perc => perc, :length => l, :velocity => v)
27
27
  end
28
28
  end
29
29
  attr_reader :seq
@@ -31,10 +31,18 @@ module Zgomot::Comp
31
31
  @seq = [seq].flatten
32
32
  end
33
33
  def method_missing(meth, *args, &blk)
34
- @seq = seq.map do |p|
34
+ result = seq.map do |p|
35
35
  p.respond_to?(meth) ? p.send(meth, *args, &blk) : p
36
36
  end
37
- self
37
+ if [:shift, :pop].include?(meth)
38
+ result
39
+ else
40
+ @seq = result
41
+ self
42
+ end
43
+ end
44
+ def map(&blk)
45
+ @seq = seq.map(&blk); self
38
46
  end
39
47
  end
40
48
  end
@@ -1,94 +1,64 @@
1
- ##############################################################################################################
2
1
  module Zgomot::Comp
3
-
4
- #####-------------------------------------------------------------------------------------------------------
5
2
  class Perc
6
-
7
- #.........................................................................................................
3
+
8
4
  PERC_MAP = {
9
- :acoustic_bass_drum => [:B,1],
5
+ :acoustic_bass_drum => [:B,1],
10
6
  :bass_drum_1 => [:C,2], :side_stick => [:Cs,2], :acoustic_snare => [:D,2],
11
7
  :hand_clap => [:Ds,2], :electric_snare => [:E,2], :low_floor_tom => [:F,2],
12
8
  :closed_hi_hat => [:Fs,2], :high_floor_tom => [:G,2], :pedal_hi_hat => [:Gs,2],
13
9
  :low_tom => [:A,2], :open_hi_hat => [:As,2], :low_mid_tom => [:B,2],
14
- :high_mid_tom => [:C,3], :crash_cymbal_1 => [:Cs,3], :high_tom => [:D,3],
15
- :ride_cymbal_1 => [:Ds,3], :chinese_cymbal => [:E,3], :ride_bell => [:F,3],
16
- :tambourine => [:Fs,3], :splash_cymbal => [:G,3], :cowbell => [:Gs,3],
10
+ :high_mid_tom => [:C,3], :crash_cymbal_1 => [:Cs,3], :high_tom => [:D,3],
11
+ :ride_cymbal_1 => [:Ds,3], :chinese_cymbal => [:E,3], :ride_bell => [:F,3],
12
+ :tambourine => [:Fs,3], :splash_cymbal => [:G,3], :cowbell => [:Gs,3],
17
13
  :crash_cymbal_2 => [:A,3], :vibraslap => [:As,3], :ride_cymbal_2 => [:B,3],
18
- :high_bongo => [:C,4], :low_bongo => [:Cs,4], :mute_hi_conga => [:D,4],
19
- :open_hi_conga => [:Ds,4], :low_conga => [:E,4], :high_timbale => [:F,4],
20
- :low_timbale => [:Fs,4], :high_agogo => [:G,4], :low_agogo => [:Gs,4],
14
+ :high_bongo => [:C,4], :low_bongo => [:Cs,4], :mute_hi_conga => [:D,4],
15
+ :open_hi_conga => [:Ds,4], :low_conga => [:E,4], :high_timbale => [:F,4],
16
+ :low_timbale => [:Fs,4], :high_agogo => [:G,4], :low_agogo => [:Gs,4],
21
17
  :cabasa => [:A,4], :maracas => [:As,4], :short_whistle => [:B,4],
22
- :long_whistle => [:C,5], :short_guiro => [:Cs,5], :long_guiro => [:D,5],
23
- :claves => [:Ds,5], :hi_woodblock => [:E,5], :low_woodblock => [:F,5],
24
- :mute_cuica => [:Fs,5], :open_cuica => [:G,5], :mute_triangle => [:Gs,5],
18
+ :long_whistle => [:C,5], :short_guiro => [:Cs,5], :long_guiro => [:D,5],
19
+ :claves => [:Ds,5], :hi_woodblock => [:E,5], :low_woodblock => [:F,5],
20
+ :mute_cuica => [:Fs,5], :open_cuica => [:G,5], :mute_triangle => [:Gs,5],
25
21
  :open_triangle => [:A,5],
26
- :R => :R,
22
+ :R => :R,
27
23
  }
28
24
 
29
- #####-------------------------------------------------------------------------------------------------------
30
25
  class << self
31
-
32
- #### self
33
- end
34
-
35
- #.........................................................................................................
36
- attr_reader :percs, :length, :velocity, :time_scale
37
-
38
- #.........................................................................................................
39
- def initialize(args)
40
- @length, @velocity, @percs = args[:length], args[:velocity], [args[:percs]].flatten
41
- @time_scale = 1.0
42
26
  end
43
27
 
44
- #.........................................................................................................
45
- def pitches
46
- percs.inject([]){|p,r| (m = Perc::PERC_MAP[r]).nil? ? p : p << m}
28
+ attr_reader :perc, :length, :velocity, :time_scale
29
+
30
+ def initialize(args)
31
+ @length, @velocity, @perc = args[:length], args[:velocity], args[:perc]
47
32
  end
48
-
49
- #.........................................................................................................
50
- def notes
51
- @notes ||= pitches.map do |p|
52
- Zgomot::Midi::Note.new(:pitch => p, :length => length, :velocity => velocity)
53
- end
33
+ def note
34
+ @note ||= Zgomot::Midi::Note.new(:pitch => Perc::PERC_MAP[perc],
35
+ :length => length,
36
+ :velocity => velocity)
54
37
  end
55
-
56
- #.........................................................................................................
57
- # transforms
58
- #.........................................................................................................
59
- def bpm_scale!(v)
60
- @time_scale = 1.0/v.to_f; self
38
+ def bpm!(v)
39
+ note.bpm!(v); self
61
40
  end
62
-
63
- #.........................................................................................................
64
- # channel and dispatch interface
65
- #.........................................................................................................
66
41
  def channel=(chan)
67
- notes.each{|n| n.channel = chan}
42
+ note.channel = chan
68
43
  end
69
-
70
- #.........................................................................................................
71
44
  def offset=(time)
72
- notes.each{|n| n.offset = time}
45
+ note.offset = time
73
46
  end
74
-
75
- #.........................................................................................................
76
47
  def time=(time)
77
- notes.each{|n| n.time = time}
48
+ note.time = time
49
+ end
50
+ def velocity!(v)
51
+ note.velocity!(v); self
52
+ end
53
+ def length!(v)
54
+ note.length!(v); self
78
55
  end
79
-
80
- #.........................................................................................................
81
56
  def length_to_sec
82
- time_scale*Zgomot::Midi::Clock.whole_note_sec/length
57
+ note.length_to_sec
83
58
  end
84
-
85
- #.........................................................................................................
86
59
  def to_midi
87
- notes.map{|n| n.to_midi}
60
+ note.to_midi
88
61
  end
89
-
90
- #### Scale
91
- end
92
62
 
93
- #### Zgomot::Comp
63
+ end
94
64
  end