music_coder 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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