Class: MultimediaParadise::Note

Inherits:
Base
  • Object
show all
Includes:
Comparable
Defined in:
lib/multimedia_paradise/multimedia/note.rb

Overview

MultimediaParadise::Note

Constant Summary collapse

NOTE_STRINGS =
#

NOTE_STRINGS

MultimediaParadise::NOTE_STRINGS

#
[
  'Ab', 'A',  'A#', 'Bb', 'B',
  'C',  'C#', 'Db', 'D',  'D#',
  'Eb', 'E',  'F',  'Gb', 'G',
  'G#'
]
ARRAY_NOTES =
#

ARRAY_NOTES

#
[
  'C', 'C#/Db', 'D', 'D#/Eb', 'E', 'F',
  'F#/Gb', 'G', 'G#/Ab', 'A', 'A#/Bb', 'B'
]
CHORD_ALIASES =
#

CHORD_ALIASES

#
{
  :min   => :minor,
  :m     => :minor,
  :maj   => :major,
  :M     => :major,
  :p     => :fifth,
  :pow   => :fifth,
  :power => :fifth,
  :'5'   => :fifth,
  :'5th' => :fifth,
  :dim   => :diminished,
  :aug   => :augmented,
  :'+'   => :augmented,

  # ======================================================================= #
  # Some aliases for the major seventh chord.
  # ======================================================================= #
  :maj_seventh   => :major_seventh,
  :major_7       => :major_seventh,
  :major_7th     => :major_seventh,
  :maj_7         => :major_seventh,
  :maj_7th       => :major_seventh,
  :maj7          => :major_seventh,
  :maj7th        => :major_seventh,
  :M7            => :major_seventh,

  :min_seventh   => :minor_seventh,
  :minor_7       => :minor_seventh,
  :minor_7th     => :minor_seventh,
  :min_7         => :minor_seventh,
  :min_7th       => :minor_seventh,
  :min7          => :minor_seventh,
  :min7th        => :minor_seventh,
  :m7            => :minor_seventh,

  :dim_seventh   => :diminished_seventh,
  :diminished_7  => :diminished_seventh,
  :diminished_7th => :diminished_seventh,
  :dim_7         => :diminished_seventh,
  :dim_7th       => :diminished_seventh,
  :dim7          => :diminished_seventh,
  :dim7th        => :diminished_seventh,
  :d7            => :diminished_seventh,

  :aug_seventh   => :augmented_seventh,
  :augmented_7   => :augmented_seventh,
  :augmented_7th => :augmented_seventh,
  :aug_7         => :augmented_seventh,
  :aug_7th       => :augmented_seventh,
  :aug7          => :augmented_seventh,
  :aug7th        => :augmented_seventh,
  :'+7'          => :augmented_seventh,

  :half_dim_seventh    => :half_diminished_seventh,
  :half_diminished_7   => :half_diminished_seventh,
  :half_diminished_7th => :half_diminished_seventh,
  :half_dim_7          => :half_diminished_seventh,
  :half_dim_7th        => :half_diminished_seventh,
  :half_dim7           => :half_diminished_seventh,
  :half_dim7th         => :half_diminished_seventh,
}
CHORD_INTERVALS =
#

CHORD_INTERVALS

#
{
  :minor              => [ :minor_third, :perfect_fifth],
  :major              => [ :major_third, :perfect_fifth],
  :fifth              => [ :perfect_fifth],
  :diminished         => [ :minor_third, :diminished_fifth],
  :augmented          => [ :major_third, :augmented_fifth],
  :major_seventh      => [ :major_third, :perfect_fifth, :major_seventh],
  :minor_seventh      => [ :minor_third, :perfect_fifth, :minor_seventh],
  :diminished_seventh => [ :minor_third, :diminished_fifth, :diminished_seventh],
  :augmented_seventh  => [ :major_third, :augmented_fifth, :minor_seventh],
  :half_diminished_seventh => [ :minor_third, :diminished_fifth, :minor_seventh]
}

Constants inherited from Base

Base::ERROR, Base::ERROR_LINE, Base::NAMESPACE, Base::USE_THIS_NAMESPACE_FOR_THE_COLOURS, Base::USE_THIS_NAMESPACE_FOR_THE_CORE_COLOURS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

[], #actions, #append_what_into, #be_silent, #be_verbose?, #beautiful_url, #cartoons_directory?, #clear_the_internal_hash, #cliner, #cliner_with_time_stamp, #colourized_comment, #copy_file, #crimson, #dataset_from_file_video_collection, #dd_mm_yyyy, #debug?, #default_readlines, #directory_to_realvids?, #do_not_use_opn, #dodgerblue, #does_the_video_player_support_this_commandline?, #e, #ecomment, #ecrimson, #efancy, #enable_debug, #ensure_main_encoding, #ensure_that_the_output_directory_exists, #eparse, #erev, #esystem, #ewarn, #file_video_collection?, #filter_for_audio_files, #filter_for_video_files, #forestgreen, #gold, #grey, #hh_mm_ss, #home_x_video?, #indianred, #infer_the_namespace, #internal_hash?, #is_audio_file?, #is_mkv?, #is_mp3?, #is_mp4?, #is_multimedia_file?, #is_on_roebe?, #is_video_file?, #konsole_colour_peru, #lightblue, #lightgreen, #load_yaml, #local_audio_directory?, #log_dir?, #map_symbol_to_locally_existing_file, #mediumorchid, #mediumpurple, #mediumslateblue, #mkdir, #move_file, #namespace?, #no_file_exists, #no_file_exists_at, #olive, #olivedrab, #opne, #opnecomment, #opnn, #orange, #palegoldenrod, #palegreen, #powderblue, #project_base_directory?, #rds, #register_sigint, #remove_file, #report_pwd, #reset_the_internal_hash, #return_all_video_files, #return_pwd, #return_random_video, #rev, #royalblue, #run, #save_what_into, #sdir, #seagreen, #seconds_to_time_format, #select_only_video_files_from, #set_be_verbose, #set_use_colours, #sfancy, #sfile, #simp, #skyblue, #slateblue, #springgreen, #steelblue, #swarn, #teal, #time_right_now, #to_hh_mm_ss, #tomato, #true_rev, #try_to_rename_kde_konsole_tab, #ucliner, #use_colours?, #use_opn?, #use_which_video_player?, #verbose_truth, #video_collection?, #violet, #yaml_directory?, #yel

Methods included from CommandlineArgumentsModule

#all_input_starts_with_a_number?, #commandline_arguments?, #commandline_arguments_as_a_string, #first_argument?, #first_non_hyphened_commandline_argument?, #set_commandline_arguments

Constructor Details

#initialize(descriptor, assumed_octave = nil) ⇒ Note

#

initialize

This class will create a new note.

Usage examples:

note = MultimediaParadise::Note.new(698.46) # Creates a note object
with the frequency 698.46
note = MultimediaParadise::Note.new('F#6') # Creates an F sharp note
in the 6th octave

(e.g. ‘C#4’) or a number giving the note’s frequency (e.g. 440) descriptor, use this

#

Parameters:

  • descriptor (String, Numeric)

    Either a string describing the note

  • assumed_octave (Numeric, nil) (defaults to: nil)

    If no octive is given in the



151
152
153
154
155
156
157
158
# File 'lib/multimedia_paradise/multimedia/note.rb', line 151

def initialize(descriptor, assumed_octave = nil)
  reset
  self.frequency = if descriptor.is_a? Numeric
    Note.nearest_note_frequency(descriptor)
  else
    Note.calculate_frequency(descriptor, assumed_octave)
  end
end

Instance Attribute Details

#frequencyObject

Returns the value of attribute frequency.



30
31
32
# File 'lib/multimedia_paradise/multimedia/note.rb', line 30

def frequency
  @frequency
end

Class Method Details

.calculate_frequency(*args) ⇒ Object

#

calculate_frequency

#


435
436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'lib/multimedia_paradise/multimedia/note.rb', line 435

def calculate_frequency(*args)
  case args.size
  when 1
    letter, accidental, octave = parse_note_string(args[0])
  when 2
    letter, accidental, octave = parse_note_string(args[0], args[1])
  when 3
    letter, accidental, octave = args
  else
    raise ArgumentError, "Invalid octave of arguments"
  end
  distance = note_distance('A4', "#{letter}#{accidental}#{octave}")
  frequency_adjustment(440.0, distance)
end

.calculate_note(frequency, give_flat = false) ⇒ Object

#

calculate_note

#


453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'lib/multimedia_paradise/multimedia/note.rb', line 453

def calculate_note(
    frequency, give_flat = false
  )
  # ===================================================================== #
  # We could use #log(frequency / 440.0, 2), but then this is
  # possibly not supported in Ruby 1.8 anymore.
  # ===================================================================== #
  frequency_log_base_2 = Math.log(frequency / 440.0) / Math.log(2)
  distance = (ARRAY_NOTES.size * frequency_log_base_2).round
  index  = 9 + distance # 9 is index for A
  octave = 4 + (index / ARRAY_NOTES.size) # 4 is because we're using A4
  index  = (index % ARRAY_NOTES.size)

  parts = ARRAY_NOTES[index].split('/')
  note = if give_flat
    parts.last
  else
    parts.first
  end
  # "#{note}#{octave}"
  note_parts = note.split('')
  note_parts + (note_parts.size == 1 ? [nil] : []) + [octave.to_i]
end

.frequency_adjustment(start_frequency, distance) ⇒ Object

#

frequency_adjustment

#


426
427
428
429
430
# File 'lib/multimedia_paradise/multimedia/note.rb', line 426

def frequency_adjustment(start_frequency, distance)
  result = (start_frequency * (2.0 ** (distance.to_f / ARRAY_NOTES.size)))
  # Would like to use #round(2), but want to support Ruby 1.8
  (result * 100.0).round / 100.0
end

.nearest_note_frequency(frequency) ⇒ Object

#

nearest_note_frequency

#


480
481
482
483
484
# File 'lib/multimedia_paradise/multimedia/note.rb', line 480

def nearest_note_frequency(frequency)
  Note.calculate_frequency(
    Note.calculate_note(frequency).join
  )
end

.note_distance(note_string1, note_string2) ⇒ Object

#

note_distance

#


401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# File 'lib/multimedia_paradise/multimedia/note.rb', line 401

def note_distance(note_string1, note_string2)
  letter1, accidental1, octave1 = parse_note_string(note_string1)
  letter2, accidental2, octave2 = parse_note_string(note_string2)

  get_index = Proc.new { |letter, accidental|
    ARRAY_NOTES.index { |note|
      regex = case accidental
      when '#' then
        /^#{letter}#/
      when 'b' then
        /#{letter}b$/
      else
        /^#{letter}$/
      end
      note.match(regex)
    }
  }
  index1 = get_index.call(letter1, accidental1)
  index2 = get_index.call(letter2, accidental2)
  (index2 - index1) + ((octave2.to_i - octave1.to_i) * ARRAY_NOTES.size)
end

.parse_note_string(note_string, assumed_octave = nil) ⇒ Object

Note.parse_note_string



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/multimedia_paradise/multimedia/note.rb', line 382

def parse_note_string(note_string, assumed_octave = nil)
  match = note_string.match(/^([A-Ga-g])([#b]?)([0-8]?)$/)

  unless match
    raise ArgumentError, "Could not recognize the note string: #{note_string}. It may be invalid."
  end
  if match[3].empty? && assumed_octave.nil?
    raise ArgumentError, "No octave found or specified"
  end
  if match[3].to_i > 8 || (assumed_octave && !(0..8).include?(assumed_octave))
    raise ArgumentError
  end
  octave = match[3].empty? ? assumed_octave : match[3]
  [match[1].upcase, match[2] == '' ? nil : match[2], octave.to_i]
end

Instance Method Details

#<=>(other_note) ⇒ Object

#

<=>

#


177
178
179
# File 'lib/multimedia_paradise/multimedia/note.rb', line 177

def <=>(other_note)
  self.frequency <=> other_note.frequency
end

#accidental(give_flat = false) ⇒ String

#

accidental

Returns the accidental portion of the note e.g. ‘#’ or ‘b’

#

Parameters:

  • give_flat (boolean) (defaults to: false)

    Should the result give a flat? (defaults to giving a sharp)

Returns:

  • (String)

    The resulting accidental.



238
239
240
# File 'lib/multimedia_paradise/multimedia/note.rb', line 238

def accidental(give_flat = false)
  Note.calculate_note(self.frequency, give_flat)[1]
end

#adjust_by_semitones(interval) ⇒ Note

#

adjust_by_semitones

Return another note adjusted by a given interval

#

Parameters:

  • interval (Fixnum)

    Number of semitones to adjust by

Returns:

  • (Note)

    Resulting note after adjustment.



294
295
296
297
298
# File 'lib/multimedia_paradise/multimedia/note.rb', line 294

def adjust_by_semitones(interval)
  Note.new(
    Note.frequency_adjustment(self.frequency, interval)
  )
end

#chord(description) ⇒ Object

#

chord

The first argument is the chord description.

#


359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/multimedia_paradise/multimedia/note.rb', line 359

def chord(description)
  description = :major if description.to_s.empty?

  description = description.to_s
  description.downcase! unless %w( M M7 ).include? description
  description.gsub!(/[\s\-]+/, '_')
  description = description.to_sym
  intervals = CHORD_INTERVALS[description] || CHORD_INTERVALS[CHORD_ALIASES[description]]
  if intervals
    Chord.new([self] + intervals.collect {|interval| self.send(interval) })
  end
end

#distance_to(note) ⇒ Fixnum

#

distance_to

Return the distance (in semitones) to a note

#

Returns:

  • (Fixnum)

    Number of semitones



282
283
284
# File 'lib/multimedia_paradise/multimedia/note.rb', line 282

def distance_to(note)
  Note.note_distance(self.note_string, note.note_string)
end

#eql?(other_note) ⇒ Boolean

#

eql?

#

Returns:

  • (Boolean)


191
192
193
# File 'lib/multimedia_paradise/multimedia/note.rb', line 191

def eql?(other_note)
  self.frequency == other_note.frequency
end

#frequency?Boolean

#

frequency?

#

Returns:

  • (Boolean)


170
171
172
# File 'lib/multimedia_paradise/multimedia/note.rb', line 170

def frequency?
  @frequency
end

#hashObject

#

hash

#


184
185
186
# File 'lib/multimedia_paradise/multimedia/note.rb', line 184

def hash
  self.frequency.hash
end

#letter(give_flat = false) ⇒ String Also known as: letter?

#

letter

Returns the letter portion of the note e.g. ‘C’

#

Parameters:

  • give_flat (boolean) (defaults to: false)

    Should the result be based on giving a flat? (defaults to giving a sharp)

Returns:

  • (String)

    The resulting note letter



225
226
227
# File 'lib/multimedia_paradise/multimedia/note.rb', line 225

def letter(give_flat = false)
  Note.calculate_note(self.frequency, give_flat).first
end

#major_scaleObject

#

major_scale

Uses note as key to give major scale

#


325
326
327
328
329
330
331
332
333
334
# File 'lib/multimedia_paradise/multimedia/note.rb', line 325

def major_scale
  [self,
    self.major_second,
    self.major_third,
    self.perfect_fourth,
    self.perfect_fifth,
    self.major_sixth,
    self.major_seventh,
  ]
end

#minor_scaleObject

#

minor_scale

Uses note as key to give minor scale

#


343
344
345
346
347
348
349
350
351
352
# File 'lib/multimedia_paradise/multimedia/note.rb', line 343

def minor_scale
  [self,
    self.major_second,
    self.minor_third,
    self.perfect_fourth,
    self.perfect_fifth,
    self.minor_sixth,
    self.minor_seventh,
  ]
end

#note_string(give_flat = false) ⇒ String

#

note_string

Returns string representing note with letter, accidental, and octave number e.g. ‘C#5’

(defaults to giving a sharp)

#

Parameters:

  • give_flat (boolean) (defaults to: false)

    Should the result give a flat?

Returns:

  • (String)

    The resulting note string.



212
213
214
# File 'lib/multimedia_paradise/multimedia/note.rb', line 212

def note_string(give_flat = false)
  Note.calculate_note(self.frequency, give_flat).join
end

#octaveFixnum

#

octave

Returns the octive number of the note e.g. 4.

#

Returns:

  • (Fixnum)

    The resulting octive number



249
250
251
# File 'lib/multimedia_paradise/multimedia/note.rb', line 249

def octave
  Note.calculate_note(self.frequency)[2]
end

#prevNote

#

prev

Return the previous note (adjusted by one semitone down)

#

Returns:

  • (Note)

    The previous note



260
261
262
# File 'lib/multimedia_paradise/multimedia/note.rb', line 260

def prev
  Note.new(Note.frequency_adjustment(self.frequency, -1))
end

#resetObject

#

reset

#


163
164
165
# File 'lib/multimedia_paradise/multimedia/note.rb', line 163

def reset
  super()
end

#succNote Also known as: next

#

succ

Return the next note (adjusted by one semitone up)

#

Returns:

  • (Note)

    The next note



271
272
273
# File 'lib/multimedia_paradise/multimedia/note.rb', line 271

def succ
  Note.new(Note.frequency_adjustment(self.frequency, 1))
end

#to_sObject

#

to_s

#


198
199
200
# File 'lib/multimedia_paradise/multimedia/note.rb', line 198

def to_s
  self.note_string
end