Skip to content

Instantly share code, notes, and snippets.

@hzm-s
Forked from JunichiIto/karaoke_machine.rb
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hzm-s/b851139917020672eeff to your computer and use it in GitHub Desktop.
Save hzm-s/b851139917020672eeff to your computer and use it in GitHub Desktop.
class KaraokeMachine
def initialize(melody_string)
@melody = Melody.parse(melody_string)
end
def transpose(amount)
@melody.transpose(amount).present
end
end
class Melody
def self.parse(string)
notes = string.scan(/(?:[A-G]#?|[ \|])/).map do |token|
Tone.from_string(token) || RestOrBar.new(token)
end
new(notes)
end
def initialize(notes)
@notes = notes
end
def transpose(amount)
self.class.new(@notes.map {|n| n.change(amount) })
end
def present
@notes.inject("") {|melody, n| melody += n.present }
end
end
class Tone
NAMES = %w|C C# D D# E F F# G G# A A# B|
def self.from_string(string)
return nil unless NAMES.include?(string)
Tone.new(NAMES.index(string))
end
def initialize(index)
@index = index
end
def change(amount)
new_index = (@index + amount).modulo(NAMES.size)
self.class.new(new_index)
end
def present
NAMES.at(@index)
end
end
class RestOrBar < Struct.new(:string)
def change(*args)
self
end
def present
self.string
end
end
class KaraokeMachine
TONES = %w|C C# D D# E F F# G G# A A# B|
def initialize(melody)
@melody = melody
end
def transpose(amount)
@melody
.scan(/[A-G]#?|[ \|]/)
.map {|e| TONES.at((TONES.index(e) + amount) % TONES.size) rescue e }
.join
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment