music_coder 0.9.0 → 0.9.1

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.
@@ -226,23 +226,22 @@ end
226
226
  # App.out.snddists[0]
227
227
  #end
228
228
 
229
-
230
- def random_sound root_f = 440, len = beat(1), f_range = 0.2, tone_num = 1+rand(16), parts = 1+rand(3), max_delay = 0.6
231
- main = len.Dist
232
- tone_num.times do |i|
233
- main << len.Dist
234
- main.last_born << Snd.new
235
- snd = main.last_born.snd
236
- snd.length = len.to_f
237
- delay = rand*max_delay
238
- 1.times {delay*=rand}
239
- snd.toneseq.random(rand(parts), [true,false].sample, delay, 0.333)
240
- snd.tone.set_freq root_f
241
- range = root_f * f_range
242
- snd.tone.set_freq_final root_f - range/2 + rand*range
243
- snd.toneseq.amp_reduce tone_num
244
- main.last_born.clear_hits
245
- main.last_born << delay
229
+ # return random Integer in range with min and max
230
+ def rand_range max, min=0, weight =1
231
+ rand_p = max - min
232
+ weight.times {rand_p *= rand}
233
+ min + rand_p
234
+ end
235
+
236
+
237
+ #the main function. output the code block to numbered files.
238
+ #times:: number of times to run the block into a new file
239
+ def music times=1
240
+ times.times do |i|
241
+ clear
242
+ yield
243
+ render
244
+ App.out.outfile= "#{App.outpath}#{App::OUT_SND_DIR}#{i+1}#{App::EXT}"
245
+ make
246
246
  end
247
- main
248
- end
247
+ end
@@ -11,41 +11,104 @@ class Dist < Api
11
11
  persist_hits(true)
12
12
  end
13
13
 
14
+ #return a new Dist with the same hits and length but not children or sounds.
15
+ def copy
16
+ out=Dist.new
17
+ out.length = length
18
+ out.clear_hits
19
+ out.hits << hits
20
+ out
21
+ end
14
22
 
15
- #make children with the hits you need for a bar of dubstep percussion. set their #length to mine
16
- #this dist has 5 children, in order: bass drum, secondary bass drum, snare, hi hat, second hi hat
17
- def dubstep_percussion
18
- self << Dist.new # bass drum
19
- self.last_born.clear_hits
20
- self.last_born << [0.0]
21
- self << Dist.new # 2nd bass drum
22
- self.last_born.clear_hits
23
- self.last_born << [0.75, 0.875] #two last drum hits
24
- self << Dist.new # snare
25
- self.last_born.clear_hits
26
- self.last_born << [0.5] # third beat
27
- self << Dist.new # hi hat
28
- self.last_born.clear_hits
29
- self.last_born << [0.375,0.625] # off beats
30
- self << Dist.new # 2nd hi hat
31
- self.last_born.clear_hits
32
- self.last_born << [0.125,0.875] # off beats
33
- set_child_len length
34
- self
35
- end
36
-
37
-
38
- #evenly disperse each child across len by modifying the length and hits. uses #length
39
- def space_children_across
40
- len = self.length
41
- branches.times do |i|
42
- hit = i.to_f / branches
43
- self[i].length = len #(1/branches)* len + hit * len
44
- self[i].clear_hits
45
- self[i] << hit
23
+ #add children who have sounds that make a drum like sound
24
+ #weight:: 0 is lowest drum, 1 is highest
25
+ def drum weight, amp, f_range=0.0, tone_num = 1, layers=1
26
+ layers.times do |i|
27
+ self << Dist.new
28
+ flay = last_born
29
+ min_oc = 1
30
+ max_oc = 5
31
+ oran = max_oc - min_oc
32
+ pos_num = scale_notes.count * oran #possible
33
+ ind = (pos_num * weight).round
34
+ oct_ind = min_oc + ind / scale_notes.count
35
+ log "drum notes #{ind % scale_notes.count} #{oct_ind}, weight #{weight}", 3
36
+ freq = Note.new(scale_notes[ind % scale_notes.count], oct_ind).freq
37
+ flay.drumify freq, amp/layers/2, f_range, tone_num #test
38
+
46
39
  end
40
+ flay = self[0]
41
+ self << flay.copy
42
+ under_sound = last_born
43
+ under_sound << Snd.new
44
+ under_sound.snd.length = flay.snd.length
45
+ under_sound.snd.freq = flay.snd.freq
46
+ under_sound.snd.amp = amp/2.0
47
+ under_sound.snd.fade
48
+ under_sound.snd.tone.amp.exp = flay.snd.tone.amp.exp
49
+ under_sound.clear_hits # to test
50
+ # branches.times do |i|
51
+ # self[i].snd.amp=0 if i !=branches-1 # to test
52
+ # end
47
53
  end
48
54
 
55
+ #assumes an already existing Snd and HitSq, just makes the Snd more like a percussive instrument
56
+ def drumify freq, amp, f_range, tone_num
57
+ random_sound(freq, f_range, tone_num, amp)
58
+ snd.toneseq.toneparts.last.do_all {|tone|
59
+ tone.fade
60
+ tone.amp.rand_exp true #below linear
61
+ }
62
+ end
63
+ #print hits for debugging
64
+ def ph
65
+ puts hits.hits.inspect
66
+ end
67
+
68
+ #add an Snd to self with some random properties
69
+ def random_sound root_f, f_range, parts, amp, max_delay = 0.0
70
+ # tone_num.times do |i|
71
+ self << Snd.new
72
+ delay = rand*max_delay
73
+ 1.times {delay*=rand}
74
+ snd.toneseq.random(rand(parts).to_i, [true,false].sample, delay, amp, root_f+f_range*root_f, root_f-f_range*root_f)
75
+ snd.toneseq.toneparts.each do |tp|
76
+ # tp.do_all {|tone| tone.set_freq root_f}
77
+ # range = root_f * f_range
78
+ # tp.do_all {|tone| tone.set_freq_final root_f - range/2.0 + rand*range}
79
+ end
80
+ # last_born.clear_hits
81
+ # last_born << delay
82
+ # end
83
+ end
84
+
85
+ #give mel_layers children each with a unique melody in incrementing octaves.
86
+ def random_melodies min_b_len, reps, mel_layers = 4, start_octave = 2, max_amp = 0.5,
87
+ seqs_max =0, chance = 0.4, random_del_chance = 0.25, max_b_mult=4
88
+ mel_layers.times do |i|
89
+ self << Dist.new
90
+ melody = last_born
91
+ map = melody.Mapper
92
+ map.random_melody min_b_len, reps, start_octave+i, chance, max_amp/mel_layers, rand(seqs_max).to_i, max_b_mult
93
+
94
+ # each layer picks a few bars to delete every note from.
95
+ to_del = []
96
+ map.mapee(0).hits.count.times do |h|
97
+ if rand < random_del_chance
98
+ to_del << h
99
+ end
100
+ end
101
+ # to_del = [1] #test
102
+ map.each_dist do |d|
103
+ d[0].hits.delete_arr to_del
104
+ # d[0].ph
105
+ end
106
+ # puts to_del
107
+ # map.dist.branches.times {|j| todel << map[j] if j!=0 }
108
+ # map.dist >> todel
109
+ end
110
+ end
111
+
49
112
  #sets the length of all children Dist to val
50
113
  def set_child_len val
51
114
  branches.times do |i|
@@ -62,15 +125,15 @@ end
62
125
  def Mapper
63
126
  Mapper.new(self)
64
127
  end
65
- # delete another Dist
66
- def del todel
67
- @dist.snd.delete todel.dist
128
+ # delete another Dist at index ind
129
+ def del ind
130
+ @dist.snd.delete_at ind
68
131
  self
69
132
  end
70
133
  # set the total length in frames
71
134
  def length= set
72
- @dist.len = set
73
- @dist.tss.each {|tss| tss.len = set }
135
+ @dist.len = set.round
136
+ # @dist.tss.each {|tss| tss.len = set }
74
137
  self
75
138
  end
76
139
  # get the total length in frames
@@ -175,7 +238,7 @@ end
175
238
 
176
239
  }
177
240
  end
178
- # adds a dist if it's valid to do so
241
+ # adds a dist if it's valid to do so.
179
242
  def validate_dist! val
180
243
  raise "This Dist can't have children, it has sounds. " if sounds > 0
181
244
  @dist.add val
@@ -189,6 +252,9 @@ end
189
252
  when Snd
190
253
  validate_snd! toadd.toneseq
191
254
  when Dist
255
+ if toadd.length == 0 #sets his length to mine if his is 0.
256
+ toadd.length = length
257
+ end
192
258
  validate_dist! toadd.dist
193
259
  else
194
260
  return false
@@ -198,13 +264,15 @@ end
198
264
  # Delete hits, sounds or other dists from my lists.
199
265
  def del_single todel
200
266
  case todel
201
- when HitSq, Float, Integer
267
+ when HitSq, Float
202
268
  @hits >> todel
203
269
  persist_hits
204
270
  when Snd
205
271
  @dist.tss.delete todel.snd
206
272
  when Dist
207
273
  @dist.snd.delete (todel.dist)
274
+ when Integer
275
+ del todel
208
276
  else
209
277
  return false
210
278
  end
@@ -5,6 +5,16 @@ class HitSq < Api
5
5
  @hits=[]
6
6
  super
7
7
  end
8
+ def delete_arr to_del
9
+ to_del.each {|di| self.hits.delete_at di }
10
+ persist
11
+ end
12
+ # multiply all hits by mult
13
+ def * mult
14
+ hn = []
15
+ self.hits.collect! {|hit| hit = hit*mult}
16
+ persist
17
+ end
8
18
  private
9
19
  # delete value
10
20
  def del_single todel
@@ -39,6 +49,7 @@ class HitSq < Api
39
49
  end
40
50
  public
41
51
 
52
+ #chance:: how likely it is a hit will be DELETED
42
53
  def delete_random chance = 0.5
43
54
  to_del = []
44
55
  hits.each do |h|
@@ -113,6 +124,11 @@ class HitSq < Api
113
124
  end
114
125
  self
115
126
  end
127
+
128
+ def +(val)
129
+ move val
130
+ persist
131
+ end
116
132
  #return number of hits
117
133
  def count
118
134
  hits.count
@@ -121,7 +137,6 @@ class HitSq < Api
121
137
  def move(val=0.5)
122
138
  self.hits.collect! {|x|
123
139
  z = (x+val)
124
- z = (z*1000).round / 1000.0 # rounding
125
140
  x = z
126
141
  } # delay all
127
142
  self
@@ -157,6 +172,7 @@ class Array
157
172
  h<<self
158
173
  h
159
174
  end
175
+
160
176
  end
161
177
  class Integer
162
178
  #a shortcut. e.g. 4.eqly_spaced gives you HitSq#eqly_spaced(4)
@@ -10,6 +10,224 @@ class Mapper < Api
10
10
  @len=0
11
11
  self.map_to= map_to_dist if !map_to_dist.nil?
12
12
  end
13
+ #so that no mapees are a Dist, they are only Snd. it flattens the tree of Dist
14
+ def flatten
15
+ todel = []
16
+ count.times do |i|
17
+ mpe = mapee(i)
18
+ mpe.branches.times do |j|
19
+ self << mapee(i).copy
20
+ mapee_last << mpe[j].snd
21
+ end
22
+ todel << mapee(i)
23
+ end
24
+ dist >> todel
25
+ end
26
+
27
+ # trim some hits
28
+ def reduce_hits
29
+ # mapee(0).hits.delete_random(0.08) no work
30
+ mapee(0).hits.trim_both(0.10)
31
+ mapee(1).hits.trim_both(0.25) if count > 1
32
+ mapee(2).hits.trim_start(0.34) if count > 2
33
+ end
34
+
35
+ def random_melody min_b_len, reps =4, oct = 3, chance = 0.75, amp=0.5, seqs=0, max_b_mult = 4
36
+ self.length = length.to_f / reps
37
+ random_melody_hits(min_b_len, max_b_mult)
38
+ # map.random_melody_hits(beat(1.0).to_f, 0, 1.0) # max len is beat
39
+ delete_rand_dist 1.0 - chance
40
+ random_melody_notes(oct,rand(scale_notes.count))
41
+
42
+ count.times do |i|
43
+ freq = mapee(i).snd.tone.freq.start
44
+ mapee(i).snd.toneseq.random(seqs, true, 0, amp)
45
+ mapee(i).snd.toneseq.toneparts.each do |tp|
46
+
47
+ tp.tone(0).set_freq freq
48
+ tp.tone(1).set_freq freq
49
+ tp.tone(0).set_freq_final 0
50
+ tp.tone(1).set_freq_final 0
51
+
52
+ # tp.max_frames = len
53
+ # rand len
54
+ extra = 0.5 + rand
55
+ extra = 1.0 if extra > 1
56
+ tp.tone(0).frames = tp.tone.frames * extra
57
+ extra = 0.5 + rand
58
+ extra = 1.0 if extra > 1
59
+ tp.tone(1).frames = tp.tone.frames * extra
60
+ end
61
+ end
62
+
63
+ extend(reps)
64
+ transfer_hits
65
+ end
66
+
67
+ def random_melody_hits(min_inc, max_inc_mult)
68
+ upto = 0
69
+ len = @len
70
+ while upto < len
71
+ next_len =(min_inc*(2**(rand(max_inc_mult).to_i))).round# next len
72
+ if upto + next_len > len # limit to len
73
+ next_len = len - upto
74
+ end
75
+
76
+ self << next_len.Dist
77
+ last.clear_hits
78
+ last << upto.to_f / len
79
+ upto += next_len #inc
80
+ end
81
+ end
82
+
83
+ #call #random_melody_hits first.
84
+ def random_melody_notes(start_oct = 3, start_note = 0, increments = [1,0,-1])
85
+ keys = scale_notes()
86
+ note_index = start_note
87
+ first_note = Note.new(keys[note_index % keys.count], start_oct)
88
+ count.times do |i|
89
+ key = keys[note_index % keys.count]
90
+ used_note = first_note + note_index
91
+ mapee(i) << Note.new(key, used_note.octave).Snd
92
+ # puts Note.new(key, used_note.octave).inspect
93
+
94
+ #inc
95
+ dinc = increments.sample
96
+ note_index += dinc
97
+ end
98
+ end
99
+
100
+
101
+ #extend length by mult and repeat all childs hits.
102
+ def extend mult
103
+ self.length = @len*mult
104
+ dist.branches.times do |i|
105
+ hits = self[i].hits
106
+ self[i].clear_hits
107
+ mult.times do |j|
108
+ new_hits = HitSq.new
109
+ new_hits << hits
110
+ new_hits * (1.0/mult)
111
+ new_hits + (j.to_f / mult)
112
+ self[i] << new_hits
113
+ end
114
+ end
115
+ end
116
+
117
+ def transfer_hits
118
+ dist.branches.times do |i|
119
+ # hits = mapee(i).hits
120
+ # len = mapee(i).length
121
+ #
122
+ mapee(i).clear_hits
123
+ mapee(i).length = @len
124
+ mapee(i) << self[i].hits
125
+ self[i].clear_hits
126
+ self[i] << 0.0
127
+ # mapee(i).ph
128
+ end
129
+ end
130
+
131
+ def delete_rand_dist chance
132
+ del = []
133
+ each_dist do |d|
134
+ del << d if chance >= rand
135
+ end
136
+ del.each {|d| dist >> d}
137
+ end
138
+
139
+ #if no reps given, will use length to determin it.
140
+ def fully_extend_all reps=nil
141
+ dist.branches.times do |i|
142
+ hits = mapee(i).hits
143
+ len = mapee(i).length
144
+ mapee(i).clear_hits
145
+ reps = (@len.to_f / len).round if reps.nil?
146
+ mapee(i).length = @len
147
+ reps.times do |j|
148
+ new_hits = HitSq.new
149
+ new_hits << hits
150
+ new_hits * (1.0/reps)
151
+ new_hits + (j.to_f / reps)
152
+ # puts new_hits.hits.inspect
153
+ mapee(i) << new_hits
154
+ end
155
+ # puts mapee(i).hits.hits.inspect
156
+ end
157
+ end
158
+
159
+ def do_mapee
160
+ count.times {|i| yield(mapee(i))}
161
+ end
162
+
163
+
164
+ #make all drum sounds
165
+ #always will be an extra layer anyway
166
+ def drum_sounds max_amp=0.5, layers =1
167
+ tot = count
168
+ amp = max_amp.to_f / tot #out of total drums
169
+ tot.times do |i|
170
+ this_amp = amp
171
+ wei = (i+1).to_f/(tot+1)
172
+ # this_amp = max_amp if wei < 0.4 # if bass-ish
173
+ range = 0.0
174
+ seqs= 1
175
+ if wei > 0.7 # if hihat-ish
176
+ this_amp /= 3
177
+ mapee(i).drum(wei, this_amp, 0.04, 1, layers)
178
+ mapee(i)[0].snd.toneseq.tonepart(0).do_all {|tone| tone.saturations.start = 0.5 + rand(3).to_f/10}
179
+ mapee(i)[0].snd.toneseq.do_all{|tp| tp.do_all {|tone|
180
+ tone.detail = 10000
181
+ tone.amp.exp = 0.12
182
+ } }
183
+ else
184
+ if wei > 0.35 && wei < 0.65
185
+ range = 0.5
186
+ seqs= 2+rand(2)
187
+ end
188
+ mapee(i).drum(wei, this_amp, range, seqs, layers)
189
+ end
190
+ end
191
+ end
192
+
193
+ #add dists with the hits you need for a bar of techno percussion.
194
+ #len:: length of bar
195
+ #3 children, in order: bass drum, snare, hi hat
196
+ def techno_percussion len
197
+ self << len.Dist # bass drum
198
+ mapee_last.clear_hits
199
+ mapee_last << 4.eqly_spaced
200
+ # max len is full, min quarter
201
+ h_num = mapee_last.hits.count
202
+ h_num = 1 if h_num == 0
203
+ mapee_last.length= rand_range(len*0.666/h_num, len*0.11/h_num)
204
+
205
+ self << len.Dist # snare
206
+ mapee_last.clear_hits
207
+ mapee_last << [0.25,0.75]
208
+ h_num = mapee_last.hits.count
209
+ h_num = 1 if h_num == 0
210
+ mapee_last.length= rand_range(len/h_num, len/h_num/2)
211
+
212
+ self << len.Dist # hi
213
+ mapee_last.clear_hits
214
+ mapee_last << 4.eqly_spaced
215
+ mapee_last.hits.move(0.125) # offbeats
216
+ h_num = mapee_last.hits.count
217
+ h_num = 1 if h_num == 0
218
+ mapee_last.length= rand_range(len*0.666/h_num, len*0.666/h_num/2)
219
+
220
+ self
221
+ end
222
+
223
+ #evenly disperse each child across length
224
+ def fillout
225
+ count.times do |j|
226
+ self[j].clear_hits
227
+ reps = (@len.to_f / (mapee(j).length)).round
228
+ self[j] << reps.eqly_spaced
229
+ end
230
+ end
13
231
  #set the right hits to mix all children one after eachother.
14
232
  #(this can create a dj mix)
15
233
  #mixed_ammount:: the ammount of overlap between children
@@ -24,11 +242,21 @@ class Mapper < Api
24
242
  def count
25
243
  dist.branches
26
244
  end
245
+
246
+ #set length
247
+ def length= val
248
+ @len=val.round
249
+ dist.set_child_len @len
250
+ end
251
+ #get length
252
+ def length
253
+ @len
254
+ end
255
+
27
256
  #length of each child is set to length of val, and we get added to val
28
257
  #val:: a Dist
29
258
  def map_to= val
30
- @len=val.length
31
- dist.set_child_len @len
259
+ self.length= val.length
32
260
  val << dist #add me to him
33
261
  end
34
262
  #get a mapper at i from #dist
@@ -47,24 +275,35 @@ class Mapper < Api
47
275
  def mapee i=0
48
276
  dist[i][0]
49
277
  end
50
-
51
- #add dists with the hits you need for a bar of techno percussion.
52
- #len:: length of bar
53
- #3 children, in order: bass drum, snare, hi hat
54
- def techno_percussion len
278
+
279
+ #add dist with the hits you need for a bar of dubstep percussion
280
+ #this dist has 5 children, in order: bass drum, secondary bass drum, snare, hi hat, second hi hat
281
+ def dubstep_percussion len
55
282
  self << len.Dist # bass drum
56
283
  mapee_last.clear_hits
57
- mapee_last << 4.eqly_spaced
284
+ mapee_last << [0.0]
285
+ self << len.Dist # 2nd bass drum
286
+ mapee_last.clear_hits
287
+ mapee_last << [0.75, 0.875] #two last drum hits
58
288
  self << len.Dist # snare
59
289
  mapee_last.clear_hits
60
- mapee_last << [0.25,0.75]
61
- self << len.Dist # hi
290
+ mapee_last << [0.5] # third beat
291
+ self << len.Dist # hi hat
62
292
  mapee_last.clear_hits
63
- mapee_last << 4.eqly_spaced
64
- mapee_last.hits.move(0.125) # offbeats
293
+ mapee_last << [0.375,0.625] # off beats
294
+ self << len.Dist # 2nd hi hat
295
+ mapee_last.clear_hits
296
+ mapee_last << [0.125,0.875] # offbeats
65
297
  self
66
- end
298
+ end
299
+
67
300
 
301
+ #pass a block to be run on each dist
302
+ def each_dist
303
+ count.times do |i|
304
+ yield( self[i])
305
+ end
306
+ end
68
307
  private
69
308
  # Add Dist to me.
70
309
  def add_single toadd
@@ -6,6 +6,25 @@ class Snd < Api
6
6
  super
7
7
  end
8
8
 
9
+ #assumes one tone only
10
+ def freq= val
11
+ tone.set_freq val
12
+ end
13
+
14
+ #freq of first tone only
15
+ def freq
16
+ tone.freq.start
17
+ end
18
+
19
+ def amp= val
20
+ toneseq.do_all {|tp|
21
+ tp.do_all {|tone|
22
+ tone.amp.start = val
23
+ tone.amp.final = 0.0
24
+ }
25
+ }
26
+ end
27
+
9
28
  # return its TonePart.
10
29
  def tonepart i=0
11
30
  child = @snd.tonepart i
@@ -23,7 +23,7 @@ class AudioOutput
23
23
  log "phase 1 complete.", 2
24
24
  end
25
25
  def make_audio_file
26
- log "phase 2 of 2: merging all tmp files into #{App::EXT} file. == #{App.time_since}", 2
26
+ log "phase 2 of 2: merging all tmp files into #{App::EXT} file. secs:#{App.time_since}", 2
27
27
  frames_index = 0
28
28
  len = 0
29
29
  # get max len
@@ -61,6 +61,7 @@ class AudioOutput
61
61
  end
62
62
  log "CHUNK_@#{frames_index} asked for #{jump}. total: #{len}", 4
63
63
  values = filelist.root_get_value(frames_index,jump)#, jump)+
64
+
64
65
  # if values.count==0
65
66
  # puts "VALUES RETURNED 0"
66
67
  # frames_index = len # end this shit
@@ -16,8 +16,8 @@ def initialize(start=nil,final=nil,exp=0)
16
16
  @exp = exp
17
17
  end
18
18
  # randomize the exp with good values.
19
- def rand_exp
20
- self.exp = 0.20 * rand(100)
19
+ def rand_exp below_linear =[true,false].sample
20
+ self.exp = below_linear ? 0.1 + 0.9 * rand : 1+rand(20)
21
21
  end
22
22
  # set #final to a percentage of start
23
23
  def %(percent)
@@ -12,7 +12,7 @@ class FileList
12
12
  # delays of children
13
13
  attr_accessor :filelist_delays
14
14
  # I want each child in the fileslist to fill len frames from my start
15
- attr_accessor :child_len, :mark_of_death
15
+ attr_accessor :child_len, :mark_of_death, :to_del
16
16
  def initialize()
17
17
  @files = []
18
18
  @loaded_file_index = nil
@@ -22,6 +22,7 @@ class FileList
22
22
  @file_content_lens=[]
23
23
  @loaded_file_data = nil
24
24
  @mark_of_death = false
25
+ @to_del=[]
25
26
  end
26
27
 
27
28
  def root_get_value(index,size=1)
@@ -55,35 +56,41 @@ class FileList
55
56
  out=[]
56
57
  fl=filelists[i]
57
58
  App.checks+=1
58
- delay = filelist_delays[i]
59
+ delay = filelist_delays[i]
60
+
59
61
  # delay = 0 if delay.nil?
60
62
  # puts "deciding if we should go into filelist #{i+1} of #{filelists.count},"+
61
63
  # " is #{delay} <= #{index} ? "
62
64
  # puts "child len #{@child_len}"
63
65
  needed_until_in = delay - index
66
+ # puts "needed till in #{needed_until_in}"
64
67
  if needed_until_in <= 0
65
- # puts "child #{i}"# #{index-delay}"
68
+
66
69
  if fl.mark_of_death
67
70
  # puts "old count: #{filelists.count}"
68
71
  # fl.loaded_file_data=nil
69
72
  # GC.start
70
- self.filelists.delete_at i
71
- self.filelist_delays.delete_at i
72
- # puts "#{i} is dead! new count: #{filelists.count}"
73
+ self.to_del << i
74
+ # puts "#{i} is dead! new count: #{filelists.count}"
73
75
  else
74
76
  # normal result
75
77
  result =fl.get_value(index-delay,size)
76
- # puts "normal #{result.count}"
78
+
77
79
  out= result
78
80
  end
79
81
  else
80
82
  spoof_req_len = size - needed_until_in
83
+ # puts "checking if we can spoof, next move is #{size} and we will be in in #{needed_until_in}."
81
84
  if spoof_req_len > 0
85
+ # puts "checking buggy dude spoofed!! #{index}"
86
+
82
87
  # Read a smaller chunk in the futre that will be missed if we increment by size.
83
88
  index_to_get_in = needed_until_in + index
84
89
  delay_on_future_chunk = Array.new(needed_until_in, 0)
85
90
  future_chunk = fl.get_value(index_to_get_in-delay, spoof_req_len)
86
91
  # puts future_chunk.count
92
+
93
+ # puts "spoofing at #{index} for #{delay} and got #{future_chunk.count} results."
87
94
  combo = [] + delay_on_future_chunk + future_chunk
88
95
  # puts combo.count
89
96
  out= combo # with resizing, but will be chunk len anyway.
@@ -109,9 +116,14 @@ class FileList
109
116
  self.mark_of_death = true
110
117
  return []
111
118
  end
112
- filelists.each_with_index do |fl,i|
119
+ self.to_del = []
120
+ filelists.count.times do |i|
113
121
  out.add_e lookup_child(index,size,i)
114
122
  end
123
+ self.to_del.each do |i|
124
+ self.filelist_delays.delete_at i
125
+ self.filelists.delete_at i
126
+ end
115
127
  out
116
128
  end
117
129
 
@@ -4,6 +4,7 @@ class << self
4
4
  end
5
5
  # golden ratio
6
6
  self::GR = 1.61803398875 unless const_defined?(:GR)
7
+ self::GRI = 0.61803398875 unless const_defined?(:GRI)
7
8
 
8
9
  #outputs 0 to 1 increasing by the factor
9
10
  #detail:: number of times to apply division. 1 to inf
@@ -109,8 +109,12 @@ end
109
109
 
110
110
  # clears objects ready to write to file.
111
111
  def self.clear_ready
112
- App.clear_dir App::TMP_DIR
112
+ App.clear_rendered
113
113
  App.out.snddists = []
114
+ end
115
+
116
+ def self.clear_rendered
117
+ App.clear_dir App::TMP_DIR
114
118
  App.out.filelist = FileList.new
115
119
  end
116
120
 
@@ -189,6 +193,7 @@ App.checks = 0
189
193
  self.out = AudioOutput.new
190
194
  # make dirs
191
195
  require 'fileutils'
196
+ App::OUT_SND_DIR = 'sound/' unless const_defined?(:OUT_SND_DIR)
192
197
  FileUtils.mkdir_p App.outpath+"sound/"
193
198
  FileUtils.mkdir_p App::TMP_DIR
194
199
  #
@@ -72,14 +72,16 @@ end
72
72
  files=FileList.new
73
73
  raise "forgot to put a length of this sound dist" if len.nil?
74
74
  log "Warning: one of your sound distributions have no hits. on purpose? ", 3 if hits.empty?
75
- hits.each_with_index do |delay,i|
76
- delay_in_frames= (delay*len).round
75
+ hits.each_with_index do |delay, i|
76
+ delay_in_frames = (delay *len).round
77
77
  into=(i+1).to_f/hits.count
78
78
  snd.each do |sn|
79
79
  # puts "another snd dist "
80
80
  files.addlist sn.render(into), delay_in_frames
81
81
  end
82
- tss.each {|sn| files.addlist sn.render(into), delay_in_frames}
82
+ tss.each do |sn|
83
+ files.addlist sn.render(into), delay_in_frames
84
+ end
83
85
  # puts "#{ App.done} #{App.total}"
84
86
  if !tss.empty?
85
87
  App.done += 1
@@ -19,6 +19,10 @@ class TestTones < Test::Unit::TestCase
19
19
  assert_equal(-230, t.freq_final)
20
20
  t.set_freq(240)
21
21
  assert_equal(-220, t.freq_final)
22
+ t.set_freq_final (0)
23
+ assert_equal(0, t.freq.final)
24
+ t.set_freq(10)
25
+ assert_equal(0, t.freq_final)
22
26
  end
23
27
  end
24
28
  class TestNotes < Test::Unit::TestCase
@@ -25,7 +25,7 @@ end
25
25
  def set_freq (val)
26
26
  dif = freq.start - val
27
27
  freq.start = val
28
- set_freq_final freq_final(false) + dif, false
28
+ set_freq_final freq_final(false) + dif, false if freq_final !=0
29
29
  end
30
30
 
31
31
  def freq_final(is_relative=true)
@@ -113,6 +113,10 @@ end
113
113
  def detail
114
114
  wave.detail
115
115
  end
116
+ def detail= val
117
+ detail.start = val
118
+ detail.final = val
119
+ end
116
120
  # returns a buffer with a chord (collection of Tone whos collective amplitude equals
117
121
  # the amplitude set in tone) in #wd. one tone on each element
118
122
  # name:: String containing the chord name. Range, strings in Composer.chords
@@ -5,12 +5,12 @@ attr_accessor :tones
5
5
  attr_accessor :max_frames
6
6
  attr_accessor :tone_single
7
7
  attr_accessor :tone_count
8
- def initialize(m=0,t1=Tone.new,t2=Tone.new)
9
- @tones = Fader.new(t1,t2,0)
10
- @max_frames = m
11
- self.frames = m
8
+ def initialize(m=0,t1=Tone.new)
12
9
  @tone_count = 1
13
10
  @tone_single = t1
11
+ @tones = Fader.new(t1,nil,0)
12
+ @max_frames = m
13
+ self.frames = m
14
14
  end
15
15
 
16
16
  def tone i=0
@@ -18,6 +18,12 @@ def tone i=0
18
18
  i==1 ? @tones.final : @tones.start
19
19
  end
20
20
 
21
+ def two_tones
22
+ self.tone_count = 2
23
+ tones.start = tone_single
24
+ tones.final = tone_single.deep_copy
25
+ end
26
+
21
27
  # set #max_frames and frames on each Tone if 0.
22
28
  def max_frames= m
23
29
  @max_frames = m
@@ -66,6 +72,12 @@ def amp_mult(factor)
66
72
  end
67
73
  end
68
74
 
75
+ #perform the block on all tones
76
+ def do_all
77
+ yield (tone(0))
78
+ yield (tone(1))
79
+ end
80
+
69
81
 
70
82
  #return tone with mixed settings of tones#start with tones#final.
71
83
  #into:: how much of the final tone is mixed in. 0 is none. Range: 0 to 1
@@ -32,9 +32,15 @@ class ToneSeq
32
32
  make(1)
33
33
  end
34
34
 
35
+ def do_all
36
+ toneparts.each do |tp|
37
+ yield tp
38
+ end
39
+ end
40
+
35
41
  #random everything
36
42
  def random extra_detail = 5, even = false, delay=0, start_amp = 0.5,
37
- max_f = 2000, min_f = 120, max_sat=0.2, min_detail=50
43
+ max_f = 2000, min_f = 120, max_sat=0.8, min_detail=20
38
44
  make(extra_detail) # sets the lens evenly.
39
45
  frames_left = self.frames - self.frames.to_f*delay #- extra_detail+1 #minus a little so it must have 1 frame
40
46
  toneparts.count.times do |i|
@@ -55,6 +61,13 @@ class ToneSeq
55
61
  max_amp = toneparts[i-1].tone.amp.start
56
62
  end
57
63
  toneparts[i].tone.rand_amp_both max_amp, max_amp * 0.75 # not much lower
64
+
65
+ tp = toneparts[i]
66
+ tp.two_tones
67
+ tp.tone(1).rand_sat_both 3, max_sat
68
+ tp.tone(1).rand_freq_both(min_f, max_f)
69
+ tp.tone(1).rand_detail_both min_detail
70
+
58
71
  end
59
72
  join
60
73
  end
@@ -72,10 +85,11 @@ class ToneSeq
72
85
  def frames= val
73
86
  @toneparts.each {|tp| tp.frames = val}
74
87
  end
88
+
75
89
  def fade
76
90
  @toneparts.each {|tp|
77
- tp.tones.start.fade
78
- tp.tones.final.fade
91
+ tp.tone(0).fade
92
+ tp.tone(1).fade
79
93
  }
80
94
  self
81
95
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: music_coder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-08 00:00:00.000000000 Z
12
+ date: 2012-03-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sndfile
@@ -27,7 +27,15 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: 0.2.0
30
- description:
30
+ description: ! "Music Coder is a music programming library. It generates music entirely
31
+ through code in the chosen programming language (Ruby). \n There are
32
+ three main reasons a technically minded person would use Music Coder:\n Producing
33
+ music: Write scripts that mimic human creativity, and put some randomness in it,
34
+ giving you a program that can generate aesthetically pleasing music that is completely
35
+ unique in each file generated.\n Scientific exploration: Use the functions
36
+ in Music Coder to concisely apply algorithms or math to the structure and properties
37
+ of sound.\n Making samples: create samples or sections of music that
38
+ are too complex to be done by hand in graphical audio programs such as Ableton."
31
39
  email: karl.is.god@gmail.com
32
40
  executables: []
33
41
  extensions: []
@@ -80,7 +88,7 @@ rubyforge_project:
80
88
  rubygems_version: 1.8.23
81
89
  signing_key:
82
90
  specification_version: 3
83
- summary: An application to programmatically create music by coding.
91
+ summary: write programs that create music. music audio library.
84
92
  test_files:
85
93
  - lib/tests.rb
86
94
  has_rdoc: true