music_coder 0.7.0
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.
- data/lib/api/api.rb +108 -0
- data/lib/api/dist.rb +145 -0
- data/lib/api/hit_sq.rb +108 -0
- data/lib/api/note.rb +59 -0
- data/lib/api/snd.rb +62 -0
- data/lib/audio.rb +48 -0
- data/lib/audio_output.rb +110 -0
- data/lib/composer.rb +164 -0
- data/lib/fader.rb +37 -0
- data/lib/file_list.rb +202 -0
- data/lib/logger.rb +39 -0
- data/lib/math_utils.rb +64 -0
- data/lib/mixer.rb +14 -0
- data/lib/music_coder.rb +192 -0
- data/lib/snd_dist.rb +104 -0
- data/lib/tests.rb +168 -0
- data/lib/tone.rb +136 -0
- data/lib/tone_part.rb +96 -0
- data/lib/tone_seq.rb +42 -0
- data/lib/wave.rb +77 -0
- data/lib/wave_data.rb +103 -0
- metadata +85 -0
data/lib/audio.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# All disc operations.
|
2
|
+
class App
|
3
|
+
|
4
|
+
def App.open_w_audiofile file
|
5
|
+
raise "no file name to open for writting. " if file.nil? || App.fileoptions.nil?
|
6
|
+
# puts "#{file} #{App.fileoptions}"
|
7
|
+
Sndfile::File.open(file, App.fileoptions)
|
8
|
+
end
|
9
|
+
def self.m_from_array data
|
10
|
+
write_matrix = GSLng::Matrix.from_array(data)
|
11
|
+
write_matrix.transpose
|
12
|
+
end
|
13
|
+
|
14
|
+
def App.write_to_audiofile fout, array
|
15
|
+
fout.write App.m_from_array array
|
16
|
+
GC.start
|
17
|
+
end
|
18
|
+
|
19
|
+
def App.open_write(filen)
|
20
|
+
File.open(filen, 'w')
|
21
|
+
end
|
22
|
+
|
23
|
+
def App.close_write(fi)
|
24
|
+
fi.close
|
25
|
+
end
|
26
|
+
|
27
|
+
def App.split_array(array, size)
|
28
|
+
upto=0
|
29
|
+
ammont=array.count
|
30
|
+
jump=size
|
31
|
+
out = []
|
32
|
+
while upto < ammont do
|
33
|
+
# puts "upto #{upto} amount #{ammont}"
|
34
|
+
jump = ammont - upto if upto+jump >= ammont
|
35
|
+
# puts "array range #{upto} to #{upto+jump-1}"
|
36
|
+
out << array[upto..upto+jump-1]
|
37
|
+
upto+=jump
|
38
|
+
end
|
39
|
+
out
|
40
|
+
end
|
41
|
+
def App.read_chunk_of(array, start=0, chunk_size)
|
42
|
+
array[start..start+chunk_size-1]
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'sndfile'
|
data/lib/audio_output.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
class AudioOutput
|
2
|
+
# add all other fls to this
|
3
|
+
attr_accessor :filelist
|
4
|
+
#this didn't need to be an array, but maybe use it for track mixing?
|
5
|
+
attr_accessor :snddists
|
6
|
+
attr_accessor :outfile
|
7
|
+
# of file write
|
8
|
+
attr_accessor :percent_complete
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
@snddists = []
|
12
|
+
@outfile = nil
|
13
|
+
@filelist= FileList.new
|
14
|
+
@percent_complete = 0
|
15
|
+
end
|
16
|
+
def render
|
17
|
+
log "phase 1 of 2: render sounds", 2
|
18
|
+
App.done=0
|
19
|
+
App.total=0
|
20
|
+
snddists.each {|snddist| App.total+=snddist.tally_frames}
|
21
|
+
# puts "App.total #{App.total}" # Only for progress bar
|
22
|
+
snddists.each {|snddist| self.filelist.addlist snddist.render }
|
23
|
+
log "phase 1 complete.", 2
|
24
|
+
end
|
25
|
+
def make_audio_file
|
26
|
+
log "phase 2 of 2: merging all tmp files into #{App::EXT} file. == #{App.time_since}", 2
|
27
|
+
frames_index = 0
|
28
|
+
len = 0
|
29
|
+
# get max len
|
30
|
+
snddists.each { |sn| len = sn.len if sn.len > len }
|
31
|
+
len = len.round
|
32
|
+
fout = App.open_w_audiofile outfile
|
33
|
+
App.checks = 0 # for performance testing
|
34
|
+
last_jump=0
|
35
|
+
while frames_index < len
|
36
|
+
|
37
|
+
if frames_index + App::CHUNK_SIZE >= len
|
38
|
+
# set jump to finish it off since it's under chunk size
|
39
|
+
rest = len - frames_index #1 min, chunk_size max.
|
40
|
+
jump = rest
|
41
|
+
log "capping chunk size at #{jump}", 4
|
42
|
+
else
|
43
|
+
jump=App::CHUNK_SIZE
|
44
|
+
end
|
45
|
+
|
46
|
+
values_for_write = []
|
47
|
+
# while values_for_write.count < jump
|
48
|
+
# if frames_index-last_jump >= jump
|
49
|
+
# puts "frames index was #{frames_index} jump was #{jump}"
|
50
|
+
# puts "jump neeeds to be > #{frames_index-last_jump}"
|
51
|
+
# jump = App::CHUNK_SIZE
|
52
|
+
# end
|
53
|
+
|
54
|
+
# jump=frames_index+10000
|
55
|
+
|
56
|
+
while frames_index-last_jump < jump
|
57
|
+
# minimize if too big
|
58
|
+
if frames_index-last_jump+jump > len
|
59
|
+
jump = len-frames_index-last_jump
|
60
|
+
log "minimizing this chunk to #{jump}", 4
|
61
|
+
end
|
62
|
+
log "CHUNK_@#{frames_index} asked for #{jump}. total: #{len}", 4
|
63
|
+
values = filelist.root_get_value(frames_index,jump)#, jump)+
|
64
|
+
# if values.count==0
|
65
|
+
# puts "VALUES RETURNED 0"
|
66
|
+
# frames_index = len # end this shit
|
67
|
+
# end
|
68
|
+
# puts "CHUNK recieved #{values.count} "
|
69
|
+
# puts "--> read #{values.join(', ')}"
|
70
|
+
values_for_write+= values
|
71
|
+
# puts "____#{found_vals}"
|
72
|
+
# values.add_e found_vals
|
73
|
+
# raise " couldn't find a value... fuck." if found_val.nil?
|
74
|
+
# print percent
|
75
|
+
frames_index += values.count
|
76
|
+
App.logger.print_loading_bar(frames_index, len, percent_complete)
|
77
|
+
self.percent_complete = ((frames_index.to_f/len)*100)
|
78
|
+
# values=nil
|
79
|
+
# GC.start
|
80
|
+
end
|
81
|
+
last_jump=frames_index
|
82
|
+
# puts "--> to write: #{values_for_write.count} #{frames_index} #{len}"
|
83
|
+
App.write_to_audiofile fout, values_for_write if values_for_write.count>0
|
84
|
+
# values_for_write=nil
|
85
|
+
# GC.start
|
86
|
+
end
|
87
|
+
App.close_write fout
|
88
|
+
log "performed #{App.checks} lookup checks.", 4
|
89
|
+
print_tail_info len
|
90
|
+
end
|
91
|
+
def write_text_files file=nil
|
92
|
+
file = App.outpath + "save.rb" if file.nil?
|
93
|
+
log "state save to file #{file}", 2
|
94
|
+
File.open(file, 'w') do |file|
|
95
|
+
# snddists.each do |snddist|
|
96
|
+
# file.puts YAML::dump(snddist)
|
97
|
+
# end
|
98
|
+
file.puts YAML::dump(self)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
def print_tail_info total_frames
|
102
|
+
time_taken = App.time_since
|
103
|
+
log 'wrote file: ' + outfile, 1
|
104
|
+
log 'seconds: ' + (total_frames.to_f / Composer.samplerate).round(2).to_s +
|
105
|
+
" (frames: #{(total_frames/1000).round},000)", 2
|
106
|
+
log 'time taken: ' + time_taken.round(2).to_s +
|
107
|
+
" seconds (fps: #{(total_frames/time_taken/1000).round()},000)", 2
|
108
|
+
end
|
109
|
+
|
110
|
+
end#class
|
data/lib/composer.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# contains the functions a music composer needs.
|
2
|
+
# all functions are related to music instead of audio.
|
3
|
+
class Composer
|
4
|
+
class << self
|
5
|
+
#beats per minute of the track. (Set this first thing in your input file)
|
6
|
+
attr_accessor :bpm
|
7
|
+
#fames per second
|
8
|
+
attr_accessor :samplerate
|
9
|
+
end
|
10
|
+
def self.chords
|
11
|
+
all = Hash.new
|
12
|
+
#Triads
|
13
|
+
all["maj"] = [4, 7] # major
|
14
|
+
all["min"] = [3, 7] # minor
|
15
|
+
all["aug"] = [4, 8] # augmented
|
16
|
+
all["dim"] = [3, 6] # diminished
|
17
|
+
|
18
|
+
#Seventh chords
|
19
|
+
all["dim7"] = [3, 6, 9] # diminished 7th
|
20
|
+
all["mm7"] = [3, 7, 11] # major minor 7th
|
21
|
+
all["min7"] = [3, 7, 10] # minor 7th
|
22
|
+
all["dom7"] = [4, 7, 10] # dominant 7th
|
23
|
+
all["maj7"] = [4, 7, 11] # major 7th
|
24
|
+
# half diminished
|
25
|
+
# augmented
|
26
|
+
# augmented major
|
27
|
+
|
28
|
+
all["sus4"] = [5, 7]
|
29
|
+
all["sus2"] = [2, 7]
|
30
|
+
all["6"] = [4, 7, 9]
|
31
|
+
all["m13"] = [2, 4, 7, 9, 11]
|
32
|
+
all["9#11"] = [2, 4, 6, 7, 10]
|
33
|
+
all["tonic"] = [6]
|
34
|
+
all
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.scales
|
38
|
+
all = Hash.new
|
39
|
+
all["major"] = [2,4,5,7,9,11] # 7 total
|
40
|
+
all["minor"] = [2,3,5,7,8,10]
|
41
|
+
all["chromatic"] = *(1..10) #splat
|
42
|
+
#all["ionian"] = [2,4,5,7,9,11]
|
43
|
+
all["dorian"] = [2,3,5,7,9,10]
|
44
|
+
all["phygian"] = [1,3,5,7,8,10]
|
45
|
+
all["lydian"] = [2,4,6,7,9,11]
|
46
|
+
all["mixolydian"] = [2,4,5,7,9,10]
|
47
|
+
#all["aeolian"] = [2,3,5,7,8,10]
|
48
|
+
all["locrian"] = [1,3,5,6,8,10]
|
49
|
+
all
|
50
|
+
end
|
51
|
+
|
52
|
+
#outputs the midi notes of the chord in an array
|
53
|
+
#note:: midi value of root note in chord. range: 0 to 11
|
54
|
+
def self.chord_notes(note, name = "dim7")
|
55
|
+
set=[]
|
56
|
+
out=[]
|
57
|
+
all=chords
|
58
|
+
# handle all selected
|
59
|
+
if name=="all"
|
60
|
+
all.keys.each { |val| out.push chord_notes(note, val) }
|
61
|
+
else #normal
|
62
|
+
set = all[name]
|
63
|
+
raise "Unknown scale name" if set.nil?
|
64
|
+
out = [note] # always root
|
65
|
+
set.each do |val|
|
66
|
+
out.push note+val
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
out
|
71
|
+
end
|
72
|
+
|
73
|
+
#outputs the scale name and midi notes in hash
|
74
|
+
#note:: midi value of root note. range: 0 to 11
|
75
|
+
def self.scale_notes(note, name = "major")
|
76
|
+
set=[]
|
77
|
+
out=[]
|
78
|
+
all=scales
|
79
|
+
# handle all selected
|
80
|
+
if name=="all"
|
81
|
+
all.keys.each { |val| out.push scale_notes(note, val) }
|
82
|
+
else #normal
|
83
|
+
set = all[name]
|
84
|
+
raise "Unknown scale name" if set.nil?
|
85
|
+
out = [note] # always root
|
86
|
+
set.each do |val|
|
87
|
+
out.push note+ val
|
88
|
+
end
|
89
|
+
end
|
90
|
+
out
|
91
|
+
end
|
92
|
+
|
93
|
+
# return set of chords that fit in the scale
|
94
|
+
def self.matching_chords(scale = "major", offset = 0)
|
95
|
+
all = chords
|
96
|
+
scale_n = [0] + scales[scale]
|
97
|
+
out = []
|
98
|
+
all.each do |chord|
|
99
|
+
name = chord[0]
|
100
|
+
notes=get_notes all[name], offset # lookup chord with name
|
101
|
+
out.push name if (scale_n¬es).sort==notes.sort # if all notes are in scale
|
102
|
+
end
|
103
|
+
out
|
104
|
+
end
|
105
|
+
|
106
|
+
# return an array of notes from a array of notes with an offset, adding the root note at the start.
|
107
|
+
# e.g. ([1,10,2],2) outputs [2,3,0,4] (root note is 2, 10 + 2 becomes 0, 1 + 2 is 3 etc)
|
108
|
+
def self.get_notes(notes_ar, offset = 0)
|
109
|
+
notes = [0] + notes_ar
|
110
|
+
#offset
|
111
|
+
notes.collect! do |val|
|
112
|
+
if offset >= 0
|
113
|
+
val+offset>11 ? val+offset-12 : val+offset
|
114
|
+
else
|
115
|
+
val+offset<0 ? val+offset+12 : val+offset
|
116
|
+
end
|
117
|
+
end
|
118
|
+
notes
|
119
|
+
end
|
120
|
+
|
121
|
+
# convert beats to seconds
|
122
|
+
# @beat: the beat denominator. ie 4 means 4 beats, .125 means 1 8th beat.
|
123
|
+
def self.beat(beats)
|
124
|
+
bps = (self.bpm/60.0)
|
125
|
+
return (beats) * (1.0/bps) * self.samplerate.to_f
|
126
|
+
end
|
127
|
+
|
128
|
+
#convert a note as a string to midi value
|
129
|
+
#note:: range: "A" to "G#". No a flats.
|
130
|
+
def self.note_m(note)
|
131
|
+
val=nil
|
132
|
+
note.upcase!
|
133
|
+
case note
|
134
|
+
when 'A'
|
135
|
+
val=0
|
136
|
+
when 'A#'
|
137
|
+
val=1
|
138
|
+
when 'B'
|
139
|
+
val=2
|
140
|
+
when 'C'
|
141
|
+
val=3
|
142
|
+
when 'C#'
|
143
|
+
val=4
|
144
|
+
when 'D'
|
145
|
+
val=5
|
146
|
+
when 'D#'
|
147
|
+
val=6
|
148
|
+
when 'E'
|
149
|
+
val=7
|
150
|
+
when 'F'
|
151
|
+
val=8
|
152
|
+
when 'F#'
|
153
|
+
val=9
|
154
|
+
when 'G'
|
155
|
+
val=10
|
156
|
+
when 'G#'
|
157
|
+
val=11
|
158
|
+
else
|
159
|
+
raise "Unknown note name recieved."
|
160
|
+
end
|
161
|
+
val
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
data/lib/fader.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# An initial value, a
|
2
|
+
class Fader
|
3
|
+
# The initial value.
|
4
|
+
attr_accessor :start
|
5
|
+
# The final value.
|
6
|
+
attr_accessor :final
|
7
|
+
# The exponential rate it fades from initial to final.
|
8
|
+
# range:: +0
|
9
|
+
# 0 is linear.
|
10
|
+
# higher than 1 means it reachs the final later than linear.
|
11
|
+
# less than 1 means it reachs the final sooner than linear.
|
12
|
+
attr_accessor :exp
|
13
|
+
def initialize(start=nil,final=nil,exp=0)
|
14
|
+
@start = start
|
15
|
+
@final = final
|
16
|
+
@exp = exp
|
17
|
+
end
|
18
|
+
# set #final to a percentage of start
|
19
|
+
def %(percent)
|
20
|
+
self.final = start.to_f*(percent/100.0)
|
21
|
+
end
|
22
|
+
# operate on both start and final
|
23
|
+
def *(mul=0.5)
|
24
|
+
self.start *= mul
|
25
|
+
self.final *= mul
|
26
|
+
end
|
27
|
+
# getter
|
28
|
+
def exp
|
29
|
+
@exp==0 ? nil : @exp
|
30
|
+
end
|
31
|
+
def exp_no_nil
|
32
|
+
@exp.nil? ? 0 : @exp
|
33
|
+
end
|
34
|
+
def is_eql(other)
|
35
|
+
vars_eql?(other)
|
36
|
+
end
|
37
|
+
end
|
data/lib/file_list.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
|
2
|
+
# tree
|
3
|
+
class FileList
|
4
|
+
# ONLY WITH NO CHILDREN
|
5
|
+
attr_accessor :files
|
6
|
+
attr_accessor :file_content_lens
|
7
|
+
attr_accessor :loaded_file_index
|
8
|
+
attr_accessor :loaded_file_data
|
9
|
+
|
10
|
+
# N CHILDREN
|
11
|
+
attr_accessor :filelists
|
12
|
+
# delays of children
|
13
|
+
attr_accessor :filelist_delays
|
14
|
+
# I want each child in the fileslist to fill len frames from my start
|
15
|
+
attr_accessor :child_len, :mark_of_death
|
16
|
+
def initialize()
|
17
|
+
@files = []
|
18
|
+
@loaded_file_index = nil
|
19
|
+
@filelists = []
|
20
|
+
@filelist_delays = []
|
21
|
+
@child_len = 0
|
22
|
+
@file_content_lens=[]
|
23
|
+
@loaded_file_data = nil
|
24
|
+
@mark_of_death = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def root_get_value(index,size=1)
|
28
|
+
out=get_value(index,size)
|
29
|
+
if out.count < 1
|
30
|
+
# raise "Error looking up a value at that index. fatal. index #{index}, size #{size}."
|
31
|
+
out=Array.new(size,0)
|
32
|
+
end
|
33
|
+
out
|
34
|
+
end
|
35
|
+
# return the value, index frames into your files. recursive.
|
36
|
+
def get_value(index,size=1)
|
37
|
+
# puts "requested #{size}"
|
38
|
+
out = []
|
39
|
+
|
40
|
+
if files.empty? # has children
|
41
|
+
out=lookup_children(index,size)
|
42
|
+
# raise "Child filelist failed at index #{index}, size #{size}." if out.count < 1
|
43
|
+
else # no children, just files
|
44
|
+
# puts "looked something up"
|
45
|
+
out = get(index,size)
|
46
|
+
# puts "retrieved #{out.count} frames from object files on disk"
|
47
|
+
# puts "got #{out.count}"
|
48
|
+
# puts "=>> no children, real files found value #{out}"
|
49
|
+
end
|
50
|
+
# puts "valuse #{out}"
|
51
|
+
out
|
52
|
+
end
|
53
|
+
|
54
|
+
def lookup_child(index,size,i)
|
55
|
+
out=[]
|
56
|
+
fl=filelists[i]
|
57
|
+
App.checks+=1
|
58
|
+
delay = filelist_delays[i]
|
59
|
+
# delay = 0 if delay.nil?
|
60
|
+
# puts "deciding if we should go into filelist #{i+1} of #{filelists.count},"+
|
61
|
+
# " is #{delay} <= #{index} ? "
|
62
|
+
# puts "child len #{@child_len}"
|
63
|
+
needed_until_in = delay - index
|
64
|
+
if needed_until_in <= 0
|
65
|
+
# puts "child #{i}"# #{index-delay}"
|
66
|
+
if fl.mark_of_death
|
67
|
+
# puts "old count: #{filelists.count}"
|
68
|
+
# fl.loaded_file_data=nil
|
69
|
+
# 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
|
+
else
|
74
|
+
# normal result
|
75
|
+
result =fl.get_value(index-delay,size)
|
76
|
+
# puts "normal #{result.count}"
|
77
|
+
out= result
|
78
|
+
end
|
79
|
+
else
|
80
|
+
spoof_req_len = size - needed_until_in
|
81
|
+
if spoof_req_len > 0
|
82
|
+
# Read a smaller chunk in the futre that will be missed if we increment by size.
|
83
|
+
index_to_get_in = needed_until_in + index
|
84
|
+
delay_on_future_chunk = Array.new(needed_until_in, 0)
|
85
|
+
future_chunk = fl.get_value(index_to_get_in-delay, spoof_req_len)
|
86
|
+
# puts future_chunk.count
|
87
|
+
combo = [] + delay_on_future_chunk + future_chunk
|
88
|
+
# puts combo.count
|
89
|
+
out= combo # with resizing, but will be chunk len anyway.
|
90
|
+
else
|
91
|
+
# Will be handled in future chunks.
|
92
|
+
# out.add_e Array.new(2,0)
|
93
|
+
# puts "not above delay"
|
94
|
+
# puts "c #{delay-index}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
out
|
98
|
+
end
|
99
|
+
|
100
|
+
def lookup_children(index,size)
|
101
|
+
out = []
|
102
|
+
if filelists.count==0
|
103
|
+
#no file lists, so fill with 0s to len
|
104
|
+
sil_amount = size
|
105
|
+
sil_amount = child_len if child_len < sil_amount && child_len != 0 #limit silence to my length
|
106
|
+
sil_amount
|
107
|
+
out = Array.new(sil_amount-index,0) if sil_amount-index > 0
|
108
|
+
### puts "set mark of death, returning silence #{sil_amount}, my length: #{child_len}"
|
109
|
+
self.mark_of_death = true
|
110
|
+
return []
|
111
|
+
end
|
112
|
+
filelists.each_with_index do |fl,i|
|
113
|
+
out.add_e lookup_child(index,size,i)
|
114
|
+
end
|
115
|
+
out
|
116
|
+
end
|
117
|
+
|
118
|
+
def get(index, size=1)
|
119
|
+
# out=Array.new(1,0)
|
120
|
+
out=[]
|
121
|
+
# not opened yet
|
122
|
+
if loaded_file_index.nil?
|
123
|
+
# App.logger.print_and_flush "|t|"
|
124
|
+
load_from_file(0)
|
125
|
+
end
|
126
|
+
|
127
|
+
#still got data to write in THIS file
|
128
|
+
if current_index_fits_opended_file?(index)
|
129
|
+
out = (read_data_at index, size)
|
130
|
+
# puts "fl-no-child: normal read #{out}"
|
131
|
+
|
132
|
+
#need to load next file (index is higher than current)
|
133
|
+
else
|
134
|
+
# theres more files to load
|
135
|
+
if files.count > loaded_file_index+1
|
136
|
+
load_from_file(loaded_file_index+1)
|
137
|
+
out = (read_data_at index, size)
|
138
|
+
# puts "fl-no-child: file #{loaded_file_index} is finished. load next. found val #{out}"
|
139
|
+
else # no more files, index is past
|
140
|
+
self.mark_of_death =true
|
141
|
+
# puts "fl-no-child: marking for dead!!!"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
out
|
145
|
+
end
|
146
|
+
|
147
|
+
#return:: total len of this TrackSection
|
148
|
+
#nil is error
|
149
|
+
def get_content_len
|
150
|
+
child_len.nil? ? file_content_lens.reduce(:+) : child_len
|
151
|
+
end
|
152
|
+
|
153
|
+
def current_index_fits_opended_file?(index) # all that have been opened are tallied
|
154
|
+
index < file_content_lens[0..loaded_file_index].reduce(:+)
|
155
|
+
end
|
156
|
+
|
157
|
+
# returning array of size
|
158
|
+
def read_data_at (index,size=2)
|
159
|
+
lookup=loaded_file_index==0 ? index : index-file_content_lens[0..loaded_file_index-1].reduce(:+)
|
160
|
+
#index - all other lengths, so we get a relative index.
|
161
|
+
rb = loaded_file_data.count-1 # right bound
|
162
|
+
# puts "largest possible #{rb}, lookup #{lookup}"
|
163
|
+
jump = lookup+size-1
|
164
|
+
jump = rb if jump > rb
|
165
|
+
result=loaded_file_data[lookup..jump]
|
166
|
+
# puts "#{lookup } #{jump} #{result}"
|
167
|
+
# puts "giving data size #{result.count}"
|
168
|
+
result
|
169
|
+
end
|
170
|
+
|
171
|
+
#index
|
172
|
+
def load_from_file(fi)
|
173
|
+
f=File.new(files[fi], "r")
|
174
|
+
data=f.gets(nil)
|
175
|
+
f.close
|
176
|
+
self.loaded_file_index = fi
|
177
|
+
parse_loaded data
|
178
|
+
end
|
179
|
+
|
180
|
+
def parse_loaded data
|
181
|
+
self.loaded_file_data=Marshal.load(data)
|
182
|
+
end
|
183
|
+
|
184
|
+
def addlist list, delay=0
|
185
|
+
self.filelists.push list
|
186
|
+
self.filelist_delays.push delay.to_i
|
187
|
+
end
|
188
|
+
|
189
|
+
def write(wave_data,delay=0)
|
190
|
+
full=wave_data.dps
|
191
|
+
# puts "--> values: #{full.join(', ')}"
|
192
|
+
spli=App.split_array(full, App::CHUNK_SIZE)
|
193
|
+
spli.each_with_index do |array,i|
|
194
|
+
self.files.push "../tmp/#{object_id}_#{i}"
|
195
|
+
self.file_content_lens.push array.count
|
196
|
+
File.open(self.files.last, 'w') do |fout|
|
197
|
+
fout.puts Marshal.dump(array)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
# puts "written #{spli.count} tmp files"
|
201
|
+
end
|
202
|
+
end
|