forked from beneggett/music_theory
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
391 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,3 +14,7 @@ | |
mkmf.log | ||
.ruby-version | ||
.ruby-gemset | ||
|
||
*.wav | ||
presentation* | ||
samples |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,18 @@ | ||
require 'wavefile' | ||
require 'active_support/all' | ||
|
||
require "music_theory/version" | ||
require "music_theory/note" | ||
require "music_theory/octave" | ||
require "music_theory/scale" | ||
require "music_theory/modes" | ||
require "music_theory/third" | ||
require "music_theory/chord" | ||
require "music_theory/harmonize" | ||
require "music_theory/output" | ||
require "music_theory/play" | ||
|
||
|
||
module MusicTheory | ||
# Your code goes here... | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
require 'music_theory/output' | ||
|
||
module MusicTheory | ||
class Chord | ||
include MusicTheory::Output | ||
|
||
attr_accessor :third, :duration, :all_notes, :output_file_name | ||
|
||
def initialize(third, options = {}) | ||
@duration = options[:duration] || 2.0 | ||
@third = third | ||
@output_file_name = options[:output_file_name] || 'chord' # File name to write (without extension) | ||
end | ||
|
||
def flatten_third | ||
third.all_notes.each {|note| note.duration = duration} | ||
new_samples = [] | ||
sample_count = third.all_notes.first.samples.count | ||
third.samples.in_groups_of(sample_count).each do |group| | ||
group.each_with_index do |value, i| | ||
new_samples[i] ||= 0 | ||
new_samples[i] += value | ||
end | ||
end | ||
|
||
max = new_samples.map {|s| s.abs }.max | ||
multiplier = 1.0 / max | ||
new_samples.map!{ |s| multiplier * s } | ||
end | ||
|
||
|
||
def samples | ||
flatten_third | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require 'music_theory/output' | ||
|
||
module MusicTheory | ||
class Harmonize | ||
include MusicTheory::Output | ||
|
||
attr_accessor :samples | ||
|
||
def initialize(*things_to_flatten) | ||
@samples = [] | ||
[*things_to_flatten].each do |group| | ||
group.each_with_index do |value, i| | ||
@samples[i] ||= 0 | ||
@samples[i] += value | ||
end | ||
end | ||
max = @samples.map {|s| s.abs }.max | ||
multiplier = 1.0 / max | ||
@samples.map!{ |s| multiplier * s } | ||
end | ||
|
||
|
||
|
||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
require 'music_theory/output' | ||
|
||
module MusicTheory | ||
class Modes | ||
include MusicTheory::Output | ||
S = 1 | ||
T = 2 | ||
I = [T, T, S, T, T, T, S] | ||
II = I.rotate | ||
III = I.rotate(2) | ||
IV = I.rotate(3) | ||
V = I.rotate(4) | ||
VI = I.rotate(5) | ||
VII = I.rotate(6) | ||
CHROMATIC = [S,S,S,S,S,S,S,S,S,S,S,S] | ||
|
||
# Map the music theory names as class methods | ||
|
||
def self.ionian; I; end | ||
self.singleton_class.send(:alias_method, :major, :ionian) | ||
def self.dorian; II; end | ||
def self.phrygian; III; end | ||
def self.lydian; IV; end | ||
def self.mixolydian; V; end | ||
def self.aeolian; VI; end | ||
self.singleton_class.send(:alias_method, :minor, :aeolian) | ||
def self.locrian; VII; end | ||
def self.chromatic; CHROMATIC; end | ||
|
||
|
||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
require 'music_theory/output' | ||
|
||
module MusicTheory | ||
class Note | ||
include MusicTheory::Output | ||
attr_accessor :frequency, :duration, :output_file_name, :distort | ||
|
||
def initialize(options = {}) | ||
@frequency = options[:frequency].to_f || 220.0 # Note frequency in Hz | ||
@duration = options[:duration] || 1.0 # Number of seconds per note | ||
@distort = options[:distort] || false | ||
@output_file_name = options[:output_file_name] || 'note' # File name to write (without extension) | ||
end | ||
|
||
def total_frames | ||
# We want 1 second of the note, so we need 1 second's worth of frames | ||
(duration * sample_rate).to_i | ||
end | ||
|
||
def cycles_per_frame | ||
# each frame, we want this fraction of a cycle: | ||
frequency / sample_rate | ||
end | ||
|
||
def sine_wave_cycle | ||
# A cycle is a full sine wave, which is 2π radians: | ||
2 * Math::PI * cycles_per_frame | ||
end | ||
|
||
def samples | ||
# So to create a note that's one second long, we need to write out all the samples in the sine waves | ||
phase = 0 | ||
samples = total_frames.times.map do | ||
sample = (Math.sin phase).to_f | ||
phase += sine_wave_cycle | ||
sample | ||
end | ||
samples = distort!(samples) if distort | ||
samples | ||
end | ||
|
||
def distort!(samples) | ||
samples.map do |sample| | ||
negative = (sample) < 0 | ||
sample *= 8.to_f | ||
if sample.abs > 5 | ||
sample = 5 | ||
sample *= -1 if negative | ||
end | ||
sample /= 8.to_f | ||
end | ||
end | ||
|
||
def scale | ||
|
||
end | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
require 'music_theory/output' | ||
|
||
module MusicTheory | ||
class Octave | ||
include MusicTheory::Output | ||
attr_accessor :starting_note, :number_of_octaves, :direction, :output_file_name, :all_notes | ||
|
||
def initialize(options = {}) | ||
@starting_note = options[:starting_note] || MusicTheory::Note.new # Note to start on | ||
@number_of_octaves= options[:number_of_octaves] || 2 # Number of octaves to repeat | ||
@direction = options[:direction] || 'asc' # Number of seconds per note | ||
@output_file_name = options[:output_file_name] || 'octave' # File name to write (without extension) | ||
@all_notes = [] | ||
all_notes << starting_note | ||
number_of_octaves.to_i.times do | ||
new_note = all_notes.last.clone | ||
if direction == 'asc' | ||
new_note.frequency = all_notes.last.frequency * 2 | ||
elsif direction == 'desc' | ||
new_note.frequency = all_notes.last.frequency / 2 | ||
end | ||
all_notes << new_note unless new_note.frequency > 20000 | ||
end | ||
end | ||
|
||
def samples | ||
all_notes.map(&:samples).flatten | ||
end | ||
|
||
def sample_rate | ||
starting_note.sample_rate | ||
end | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
module MusicTheory | ||
module Output | ||
|
||
def sample_rate | ||
22050 | ||
end | ||
|
||
def format | ||
WaveFile::Format.new :mono, :pcm_16, sample_rate | ||
end | ||
|
||
def buffer_format | ||
WaveFile::Format.new :mono, :float, sample_rate | ||
end | ||
|
||
def output_track | ||
WaveFile::Writer.new "#{output_file_name || 'music'}.wav", format do |writer| | ||
buffer = WaveFile::Buffer.new samples, buffer_format | ||
writer.write buffer | ||
end | ||
end | ||
|
||
def play | ||
output_track # unless File.file?("#{output_file_name}.wav") | ||
`afplay #{output_file_name}.wav` | ||
nil | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
require 'music_theory/output' | ||
|
||
module MusicTheory | ||
class Play | ||
include MusicTheory::Output | ||
|
||
attr_accessor :samples, :output_file_name, :playable_music | ||
def initialize(playable_music = [], options = {} ) | ||
@playable_music = playable_music | ||
@output_file_name = options[:output_file_name] || 'music' | ||
extract_samples | ||
play | ||
end | ||
|
||
def extract_samples | ||
@samples = playable_music.map { |music| music.samples }.flatten | ||
end | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
require 'music_theory/output' | ||
|
||
module MusicTheory | ||
class Scale | ||
include MusicTheory::Output | ||
attr_accessor :starting_note, :number_of_octaves, :direction, :output_file_name, :all_notes, :scale_type, :scale_notes, :distort, :duration, :frequency, :sample_rate | ||
|
||
def initialize(scale_type = :major, options = {}) | ||
@scale_type = scale_type | ||
@distort = options[:distort] || false | ||
@duration = options[:duration] || 0.5 | ||
@frequency = options[:frequency] || 220.0 | ||
@starting_note = create_new_note # Note to start on | ||
|
||
@number_of_octaves= options[:number_of_octaves] || 2 # Number of octaves to repeat | ||
@direction = options[:direction] || 'asc' # Number of seconds per note | ||
@output_file_name = options[:output_file_name] || 'scale' # File name to write (without extension) | ||
set_all_notes | ||
set_scale_notes | ||
end | ||
|
||
def third | ||
third ||= MusicTheory::Third.new self | ||
end | ||
|
||
def chord | ||
third.chord | ||
end | ||
|
||
def twelth_root_of_two | ||
(2 ** (1.0/12)) | ||
end | ||
|
||
def mode | ||
MusicTheory::Modes.send(scale_type) | ||
end | ||
|
||
def set_scale_notes | ||
@scale_notes = [all_notes.first] | ||
note_index = 0 | ||
mode.each do |interval| | ||
note_index += interval | ||
scale_notes << all_notes[note_index] | ||
end | ||
end | ||
|
||
def create_new_note | ||
MusicTheory::Note.new( frequency: frequency, duration: duration, distort: distort) | ||
end | ||
|
||
def set_all_notes | ||
@all_notes = [@starting_note] | ||
12.times do | ||
new_note = create_new_note | ||
new_note.frequency = (all_notes.last.frequency * twelth_root_of_two) | ||
all_notes << new_note | ||
end | ||
end | ||
|
||
def samples | ||
scale_notes.map(&:samples).flatten | ||
end | ||
|
||
def sample_rate | ||
starting_note.sample_rate | ||
end | ||
|
||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
require 'music_theory/output' | ||
|
||
module MusicTheory | ||
class Third | ||
include MusicTheory::Output | ||
|
||
attr_accessor :scale, :all_notes | ||
|
||
def initialize(scale) | ||
@scale = scale | ||
@all_notes = [@scale.scale_notes.first] | ||
current = 0 | ||
double_scale_notes = @scale.scale_notes * 2 | ||
@scale.mode.in_groups_of(2, false) do |group| | ||
current += group.sum | ||
all_notes << double_scale_notes[current] | ||
end | ||
all_notes.uniq! {|note| note.frequency} | ||
all_notes.sort_by! {|note| note.frequency} | ||
end | ||
|
||
|
||
def output_file_name | ||
scale.output_file_name || 'thirds' | ||
end | ||
|
||
def samples | ||
all_notes.map(&:samples).flatten | ||
# chord_samples | ||
end | ||
|
||
def chord | ||
chord ||= MusicTheory::Chord.new self | ||
end | ||
|
||
end | ||
end |
Oops, something went wrong.