Class: Multisample
- Inherits:
-
Object
- Object
- Multisample
- Defined in:
- lib/Multisample.rb
Overview
A Multisample is a collection of related Samples that can form an intrument.
Constant Summary collapse
- XFADE =
auto-xfade (usually best)
0- STRICTKEYS =
1:1 key map (usually worst)
1- KEYCURVE_GAIN =
Gain keycurve
3- KEYCURVE_POWER =
Power keycurve
4- LINE_LIMIT =
Maximum number of columns in SFZ comments before a line wrap
80
Instance Attribute Summary collapse
-
#default_path ⇒ Object
Returns the value of attribute default_path.
-
#mapping ⇒ Object
Returns the value of attribute mapping.
-
#message ⇒ Object
Returns the value of attribute message.
-
#padding ⇒ Object
Returns the value of attribute padding.
-
#transpose ⇒ Object
Returns the value of attribute transpose.
Class Method Summary collapse
-
.dir_contains_multisamples?(dir) ⇒ Boolean
returns true if the directory contains files that might be multisamples.
-
.multisample_filename?(name) ⇒ Boolean
returns true if a filename can be understood as a multisample element.
Instance Method Summary collapse
- #_transpose(note) ⇒ Object
-
#add(sample) ⇒ Object
add a Sample to the Multisample.
-
#get_xfade(sample, prev_sample, next_sample, keycurve = false) ⇒ Object
Returns SFZ opcodes to specify pitch_keycenter and xfade parameters for a region.
-
#initialize(path, name = false) ⇒ Multisample
constructor
instantiate the Multisample.
-
#sanitize_file_path(f) ⇒ Object
Sanitizes file path separators.
-
#sfz_banner ⇒ Object
Returns the Multisample's SFZ header as a string.
-
#sfz_banner_message(fulltext) ⇒ Object
Returns a formatted message formatted to the SFZ.
-
#to_s ⇒ Object
Sreturn a String representation of the Multisample.
-
#to_sfz ⇒ Object
Returns a string of SFZ elements.
-
#valid? ⇒ Boolean
Do the samples within the Multisample justify its existence?.
Constructor Details
#initialize(path, name = false) ⇒ Multisample
instantiate the Multisample
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/Multisample.rb', line 44 def initialize( path, name=false ) #TODO: Raise Exception if path not valid @path=path @samples=Array.new @name = "Unnamed Multisample" if name @name=name.chomp.gsub(/^\s*/, '').gsub(/\s*$/, '') end @mapping = XFADE = false # SFZ header message @padding = 12 # padding in semitones # include a default path? @default_path = false # Number of semitones to shift the note on the keyboard @transpose = 0 end |
Instance Attribute Details
#default_path ⇒ Object
Returns the value of attribute default_path.
39 40 41 |
# File 'lib/Multisample.rb', line 39 def default_path @default_path end |
#mapping ⇒ Object
Returns the value of attribute mapping.
39 40 41 |
# File 'lib/Multisample.rb', line 39 def mapping @mapping end |
#message ⇒ Object
Returns the value of attribute message.
39 40 41 |
# File 'lib/Multisample.rb', line 39 def end |
#padding ⇒ Object
Returns the value of attribute padding.
39 40 41 |
# File 'lib/Multisample.rb', line 39 def padding @padding end |
#transpose ⇒ Object
Returns the value of attribute transpose.
39 40 41 |
# File 'lib/Multisample.rb', line 39 def transpose @transpose end |
Class Method Details
.dir_contains_multisamples?(dir) ⇒ Boolean
returns true if the directory contains files that might be multisamples
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/Multisample.rb', line 240 def Multisample.dir_contains_multisamples?( dir ) result = false values = {} @min_samples_per_multisample = 3 Dir.foreach( dir ) do |file| if v = Multisample.multisample_filename?( file ) values[v] = 1 if( values.size >= @min_samples_per_multisample ) result = true break end end end result end |
.multisample_filename?(name) ⇒ Boolean
returns true if a filename can be understood as a multisample element
224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/Multisample.rb', line 224 def Multisample.multisample_filename?( name ) #types = Sample.suffix_regexp # test for A(#)1.wav type return NamedSample.value( name ) if NamedSample.sample?( name ) # test for Sample (0)00.wav type #if name =~ /^.*((0|1)?\d\d)\.#{types}$/i # return true if (0..127).include?( $1.to_i ) #end false end |
Instance Method Details
#_transpose(note) ⇒ Object
215 216 217 218 219 220 |
# File 'lib/Multisample.rb', line 215 def _transpose( note ) if !note.nil? and note note = note + @transpose end note end |
#add(sample) ⇒ Object
add a Sample to the Multisample
66 67 68 69 |
# File 'lib/Multisample.rb', line 66 def add( sample ) @samples.push( sample ) @samples.sort! end |
#get_xfade(sample, prev_sample, next_sample, keycurve = false) ⇒ Object
Returns SFZ opcodes to specify pitch_keycenter and xfade parameters for a region.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/Multisample.rb', line 137 def get_xfade( sample, prev_sample, next_sample, keycurve=false ) xfin_lo = false xfin_hi = false xfout_lo = false xfout_hi = false lokey = false hikey = false # calculate xfade ins from previous sample if prev_sample and ( prev_sample.value < (sample.value-1) ) mid = ( sample.value + prev_sample.value ) / 2 diff = sample.value - mid xfin_lo = mid - (diff/2) xfin_hi = mid + (diff/2) lokey = xfin_lo elsif prev_sample and ( sample.value - prev_sample.value == 1 ) lokey = sample.value else lokey = sample.value - @padding end #calculate xfade outs into next sample if next_sample and ( next_sample.value > (sample.value+1) ) mid = ( sample.value + next_sample.value ) / 2 diff = sample.value - mid xfout_hi = mid - (diff/2) xfout_lo = mid + (diff/2) hikey = xfout_hi elsif next_sample and ( next_sample.value - sample.value == 1 ) hikey = sample.value else hikey = sample.value + @padding end # depending on the distance between lokey and hikey, apply xfades # Apply tranpose value = _transpose( sample.value ) hikey = _transpose( hikey ) lokey = _transpose( lokey ) xfin_lokey = _transpose( xfin_lokey ) xfin_hikey = _transpose( xfin_hikey ) xfout_lokey = _transpose( xfout_lokey ) xfout_hikey = _transpose( xfout_hikey ) result = "pitch_keycenter=#{value} " if lokey == hikey and lokey == sample.value result = "key=#{value}" else if lokey result = result + "lokey=#{lokey} " if xfin_lo and xfin_hi result = result + "xfin_lokey=#{xfin_lo} xfin_hikey=#{xfin_hi} " end end if hikey if xfout_lo and xfout_hi result = result + "xfout_lokey=#{xfout_lo} xfout_hikey=#{xfout_hi} " end result = result + "hikey=#{hikey} " end end # add xf_keycurve, if applicable if keycurve == KEYCURVE_GAIN result = result + "xf_keycurve=gain" elsif keycurve == KEYCURVE_POWER result = result + "xf_keycurve=power" end result end |
#sanitize_file_path(f) ⇒ Object
Sanitizes file path separators.
Whilst every path separator within Ruby must be "/" (Unix), evey path separator within SFZ must be "" (DOS).
129 130 131 |
# File 'lib/Multisample.rb', line 129 def sanitize_file_path( f ) f.gsub( File::SEPARATOR, "\\" ) end |
#sfz_banner ⇒ Object
Returns the Multisample's SFZ header as a string.
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/Multisample.rb', line 301 def separator = "//----------------------------------------------------------------------------" result = "" if @name result = result + "//\n" result = result + "// "+ "*** SFZ Intrument: #{@name} ***".center(76) + "\n" result = result + "//\n" end # add optional message to SFZ header if and .chomp.size > 0 result = result + separator + "\n" result = result + ( ) end # add generator message to SFZ header result = result + separator + "\n" result = result + "// Generated on #{Time.now.strftime("%Y/%m/%d %I:%M%p") } " result = result + "by #{SFZer::NAME} v#{SFZer::VERSION} (#{SFZer::URL})\n" result = result + "#{separator}\n" result end |
#sfz_banner_message(fulltext) ⇒ Object
Returns a formatted message formatted to the SFZ
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'lib/Multisample.rb', line 328 def ( fulltext ) limit = 76 result = "" result = result + "//\n" fulltext.each_line{ |text| while text.length > limit subtext = text.slice( 0 .. ( limit - 1 ) ) text = text.slice( limit .. text.length ) # don't cut off words; break at spaces i = subtext.rindex( ' ' ) if i > ( limit / 2 ) nub = subtext.slice( i+1, subtext.length ) subtext = subtext.slice( 0..i ) text = nub + text end result = result + "// " + subtext.center( limit ) + "\n" end result = result + "// " + text.center( limit ) + "\n" } result = result + "//\n" result end |
#to_s ⇒ Object
Sreturn a String representation of the Multisample
74 75 76 |
# File 'lib/Multisample.rb', line 74 def to_s "Multisample \"#{@name}\" [#{@samples.size}]: " + @samples.sort.to_s end |
#to_sfz ⇒ Object
Returns a string of SFZ elements
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/Multisample.rb', line 81 def to_sfz result = if @default_path sanitized_path = sanitize_file_path( @path ) result = result + "\n<control>\ndefault_path=#{sanitized_path}\\\n\n" end maxfilenamesize = max_sample_filename_size #result = result + "// Keyboard/Sample mappings:\n" @samples.each_index{ |i| sample=@samples[i] prev_sample = get_previous_sample( i ) next_sample = get_next_sample( i ) result = result + "<region> sample=" + sanitize_file_path( sample.sample.ljust( maxfilenamesize + 1 ) ) if @mapping == XFADE result = result + get_xfade( sample, prev_sample, next_sample ) elsif @mapping == STRICTKEYS result = result + "key=#{ _transpose( sample.value )} " end # ***************************************** # TODO: PLACE FUTURE PER-SAMPLE LOGIC HERE # ***************************************** result = result + "\n" } result end |
#valid? ⇒ Boolean
Do the samples within the Multisample justify its existence?
116 117 118 119 120 121 122 |
# File 'lib/Multisample.rb', line 116 def valid? values = {} @samples.each{ |s| values[s.value] = s } values.size >= 3 end |