Skip to content

Commit

Permalink
Merge pull request #3 from robmckinnon/v0.1.3-moar-chords
Browse files Browse the repository at this point in the history
v0.2.0 Add further ratios and chords, circle/strings UI display, and scale names
  • Loading branch information
robmckinnon authored Dec 31, 2020
2 parents a85fd94 + 4e16fef commit 7874e3f
Show file tree
Hide file tree
Showing 15 changed files with 6,098 additions and 230 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@
### Changelog

#### v0.2.0 _giojoso geola_

* Add "circle" display - show intervals on circle spokes.
* Add "strings" display - show line lengths proportionate to interval ratios.
* K3 toggles original, circle, and strings display.
* Add M medium step to scale sequences.
* Add more just intervals and chords.
* Label scale in display with an exisiting scale name when it exists in
[MusicUtil](https://monome.org/docs/norns/api/modules/MusicUtil.html),
the [Xenharmonic Wiki](https://en.xen.wiki/w/Main_Page), or
[Scala](http://www.huygens-fokker.org/docs/modename.html).

#### v0.1.1 _einfach einem_

* Define scale as a sequence of `Ls` steps.
Expand Down
42 changes: 32 additions & 10 deletions lib/Intervals.lua
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
Intervals = {}

local BLANK = ""

function Intervals:new(scale)
local s = setmetatable({}, { __index = Intervals })

s.scale = scale
s.int_labels = {}
s.uniq_labels = {}
s.int_errors = {}
s.divisions = {}
s.ratios = {}

local division = 0
local intervals = {}
local lab_to_err = {}
local lab_to_ind = {}

s.ratios[1] = 1
for i = 1,scale.length do
division = division + scale:step_value(i)
s.divisions[i] = division
s.ratios[i+1] = fn.ratio(division, scale.edivisions)
s.ratios[i+1] = pf.ratio(division, scale.edivisions)

if (i < scale.length) then
local nearest = fn.nearest_interval2(s.ratios[i+1], ratiointervals)
local nearest = pf.nearest_interval2(s.ratios[i+1], ratiointervals)
local closeness = nearest[1]
local int_label = nearest[2]
s.int_labels[i+1] = int_label
s.int_errors[i+1] = closeness
if int_label ~= "" then
intervals[int_label] = s.ratios[i]
fn.dprint(i+1, int_label)

s.uniq_labels[i+1] = BLANK

if int_label ~= "" and int_label ~= "P1" and int_label ~= "P8" then
if (lab_to_err[int_label] == nil) then
s.uniq_labels[i+1] = int_label
lab_to_ind[int_label] = i+1
lab_to_err[int_label] = closeness
elseif (closeness < lab_to_err[int_label]) then
s.uniq_labels[lab_to_ind[int_label]] = BLANK
s.uniq_labels[i+1] = int_label
lab_to_ind[int_label] = i+1
lab_to_err[int_label] = closeness
end
pf.dprint(i+1, int_label)
end
end
end
Expand All @@ -41,6 +58,12 @@ function Intervals:interval_label(i)
return self.int_labels[ i ]
end

function Intervals:uniq_interval_label(i)
print(i)
tabutil.print(self.uniq_labels)
return self.uniq_labels[ i ]
end

function Intervals:interval_error(i)
return self.int_errors[ i ]
end
Expand Down Expand Up @@ -71,8 +94,7 @@ end
-- end
-- end
-- if match then
-- fn.dprint(lab, chord)
-- pf.dprint(lab, chord)
-- end
-- end
-- end
-- print("--")

4 changes: 2 additions & 2 deletions lib/Pitches.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ local BASE_OCTAVE = 4
Pitches = {}

function get_freqx(base_freq, edo, index, oct, base_octave)
local f = base_freq * fn.ratio(index-1, edo)
local f = base_freq * pf.ratio(index-1, edo)
if (oct < base_octave) then
f = f / (2 ^ (base_octave - oct))
elseif (oct > base_octave) then
Expand All @@ -26,7 +26,7 @@ function Pitches:new(scale, intervals, tuning, midi_start)
local base_freq = midi_to_hz(midi_start, tuning)
for oct = 0,8 do
p.octdegfreqs[oct+1] = {}
f = fn.get_freq(base_freq, scale.edivisions, scale.tonic, oct, BASE_OCTAVE)
f = pf.get_freq(base_freq, scale.edivisions, scale.tonic, oct, BASE_OCTAVE)
for deg = 1,scale.length do
index = index + 1
p.freqs[index] = f * intervals:ratio(deg)
Expand Down
82 changes: 63 additions & 19 deletions lib/Scale.lua
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
local MAX_STEPS = 16
local MIN_STEPS = 3
local MAX_STEP_SIZE = 1001
local M = 3
local L = 2
local S = 1
local LABELS = {"s", "L"}
local LABELS = {"s", "L", "M"}

Scale = {}

function Scale:new(large, small, sequence)
function Scale:new(large, small, sequence, medium)
local s = setmetatable({}, { __index = Scale })
s.step = {}
s.stepbackup = {L,L,S,L,L,L,S,L,L,L,S,L,L,L,S,L}
for i = 1, #sequence do
local char = sequence:sub(i,i)
s.step[i] = (char == "L" and L) or S
s.step[i] = (char == "L" and L) or ( (char == "M" and M) or S )
end
s.large = large
s.medium = medium or large
s.small = small
s.length = #sequence
s.divisions = {}
s.edivisions = nil
s.tonic = 1
s.mode = 1
s.max_steps = 12
s.min_steps = 3
return s
end

function Scale:has_medium()
for i = 1, #self.step do
if self.step[ self:offset(i) ] == M then
return true
end
end
return false
end

function Scale:step_size(i)
return LABELS[self.step[ self:offset(i) ]]
end
Expand All @@ -38,7 +49,7 @@ function Scale:sequence()
end

function Scale:step_value(i)
return (self.step[ self:offset(i) ] == L and self.large) or self.small
return (self.step[ self:offset(i) ] == L and self.large) or ( (self.step[ self:offset(i) ] == M and self.medium) or self.small )
end

function Scale:offset(i)
Expand All @@ -51,13 +62,25 @@ function Scale:offset(i)
else
return offset
end
end
end
end

function Scale.set_max_steps(max)
self.max_steps = max
end


function Scale.set_min_steps(min)
self.min_steps = min
end

function Scale:set_large(l)
self.large = l
end

function Scale:set_medium(m)
self.medium = m
end

function Scale:set_small(s)
self.small = s
end
Expand Down Expand Up @@ -95,7 +118,8 @@ end
function Scale:change_step(d, i)
local index = self:offset(i)
local orig = self.step[ index ]
self.step[ index ] = util.clamp(self.step[ index ]+d, S, L)
self.step[ index ] = util.clamp(self.step[ index ]+d, S, M)

self.stepbackup[ index ] = self.step[ index ]
local changed = orig ~= self.step[ index ]
if changed then
Expand All @@ -107,13 +131,27 @@ end
function Scale:change_large(d)
local orig = self.large
-- local value = self.large + d
-- while fn.gcd(self.small,value)~=1 do
-- while pf.gcd(self.small,value)~=1 do
-- value = value + d
-- end
-- maxi = (d==1 and value) or (self.small + 1)
self:set_large(util.clamp(self.large + d, self.small + 1, self.large + 1))

local changed = self.large~=orig
if changed then
if self.large <= self.medium then
self:set_medium(util.clamp(self.large - 1, self.small + 1, self.large))
end
self:update_edo()
end
return changed
end

function Scale:change_medium(d)
local orig = self.medium
self:set_medium(util.clamp(self.medium + d, self.small + 1, (self.large == (self.small + 1) and self.large or (self.large-1) ) ))

local changed = self.medium~=orig
if changed then
self:update_edo()
end
Expand All @@ -123,14 +161,21 @@ end
function Scale:change_small(d)
local orig = self.small
local value = self.small + d
-- while fn.gcd(value,self.large)~=1 do
-- while pf.gcd(value,self.large)~=1 do
-- value = value + d
-- end

self:set_small(util.clamp(value, 1, self.large - 1))


if self:has_medium() then
self:set_small(util.clamp(value, 1, self.medium - 1))
else
self:set_small(util.clamp(value, 1, self.large - 1))
end

local changed = self.small~=orig
if changed then
if self.small >= self.medium then
self:set_medium(util.clamp(self.small + 1, self.small + 1, self.large))
end
self:update_edo()
end
return changed
Expand All @@ -139,10 +184,10 @@ end
function Scale:change_length(d)
local orig = self.length
if d == 1 then
self.length = util.clamp(self.length + 1, 1, MAX_STEPS)
self.length = util.clamp(self.length + 1, 1, self.max_steps)
end
if d == -1 then
self.length = util.clamp(self.length - 1, MIN_STEPS, self.length)
self.length = util.clamp(self.length - 1, self.min_steps, self.length)
end

local changed = self.length~=orig
Expand All @@ -152,12 +197,11 @@ function Scale:change_length(d)
self.step[self.length] = self.stepbackup[self.length] or L
end
if d == -1 then
if (self.length > MIN_STEPS) then
if (self.length > self.min_steps) then
table.remove(self.step, #self.step)
end
end
self:update_edo()
end
return changed
end

25 changes: 14 additions & 11 deletions lib/ScaleIntervals.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,29 @@ ScaleIntervals = {}

function ScaleIntervals:new(scale)
local s = setmetatable({}, { __index = ScaleIntervals })
local sscale = Scale:new(scale.large, scale.small, scale:sequence())

local sscale = Scale:new(scale.large, scale.small, scale:sequence(), scale.medium)
sscale:update_edo()
s.degree_to_mode = {}
s.degree_intervals = {}
local mode = nil
local tmp = nil
for deg = 1,scale.length do
fn.dprint("deg", deg)
pf.dprint("deg", deg)
mode = (scale.mode + deg - 1) % scale.length
if mode == 0 then
mode = scale.length
end
fn.dprint("mode", mode)
pf.dprint("mode", mode)
s.degree_to_mode[deg] = mode
sscale:set_mode(mode)
fn.dprint("smode", sscale.mode)
fn.dprint(":sequence()", sscale:sequence())
fn.dprint(Intervals.new)
pf.dprint("smode", sscale.mode)
pf.dprint(":sequence()", sscale:sequence())
pf.dprint(Intervals.new)
tmp = Intervals:new(sscale)
fn.dprint("tmp", tmp)
pf.dprint("tmp", tmp)
s.degree_intervals[deg] = tmp
fn.dprint("int", s.degree_intervals[deg])
pf.dprint("int", s.degree_intervals[deg])
end

return s
Expand All @@ -42,7 +42,7 @@ function ScaleIntervals:intervals(deg)
deg = deg or 1
return self.degree_intervals[deg]
end

function ScaleIntervals:ratio(i, deg)
return self:intervals(deg).ratios[ i ]
end
Expand All @@ -55,11 +55,14 @@ function ScaleIntervals:interval_label(i, deg)
return self:intervals(deg).int_labels[ i ]
end

function ScaleIntervals:uniq_interval_label(i, deg)
return self:intervals(deg).uniq_labels[ i ]
end

function ScaleIntervals:interval_error(i, deg)
return self:intervals(deg).int_errors[ i ]
end

function ScaleIntervals:nearest_degree_to(r, threshold)
return self.degree_intervals[1]:nearest_degree_to(r, threshold)
end

Loading

0 comments on commit 7874e3f

Please sign in to comment.