Julia Code for Visualizing Harmony

Library that derives the frequencies of notes

CC0
To the extent possible under law, Lennon Wotzke has waived all copyright and related or neighboring rights to this work. This work is published from: Canada.

Sample codeResult
A(2)110.0
A(3)220.0
A()440.0
C()261.6255653005986
B(sharp)523.2511306011972
B(sharp, 3)261.6255653005986
D(4, doubleflat)261.6255653005986
major(D(4))3-element Vector{Float64}:
293.6647679174076
369.9944227116344
440.0
minor(440)3-element Vector{Float64}:
440.0
523.2511306011972
659.2551138257398
# To the extent possible under law, Lennon Wotzke has waived all copyright and related or neighboring rights to this work. This work is published from: Canada.

A4 = 440

doubleflat = -1/6
flat = -1/12
natural = 0.0
sharp = 1/12
doublesharp = 1/6

frequency_of(note_offset::Real, octave_number::Integer=4, alteration::AbstractFloat=0.0) = A4* 2^( octave_number-4 + alteration + note_offset/12 )
frequency_of(note_offset::Real, alteration::AbstractFloat, octave_number::Integer=4) = frequency_of(note_offset, octave_number, alteration)

A(params...) = frequency_of(0, params...)
B(params...) = frequency_of(2, params...)
C(params...) = frequency_of(-9, params...)
D(params...) = frequency_of(-7, params...)
E(params...) = frequency_of(-5, params...)
F(params...) = frequency_of(-4, params...)
G(params...) = frequency_of(-2, params...)

major(x) = [x, x*2^(4/12), x*2^(7/12)]

minor(x) = [x, x*2^(3/12), x*2^(7/12)]

Code for Visualizing Chords

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Sample codeEffect
var = harmony_vis(nothing, 110, 220, 440)Frequencies 110, 220, and 440 used to create an image and store it as variable “var”
var = harmony_vis(nothing, C(3), D(flat, 3), G(3))
save(“test_image.png”, var)
Notes C3, Db3, and G3 used to create an image, store it as “var”, and also save it as a PNG file called “test_image.png” (Julia assumes the formatting based on the file extension)
save(“test_image.jpg”, harmony_vis(major(C(4))…, B(4)) )JPG image saved of a C major seven chord (C E G B)
save(“test_image.bmp”, harmony_vis(C(2), major(C(4))…) )Bitmap image save of a C major chord compared against the base note C(2).

Gallery of example images

# This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

# Required:
# the two Julia packages to be imported: Colors and Images
# You will also want to include the above code. You could copy it into the same file, or make a separate file, say "note_definitions.jl", and import it by uncommenting the next line:
# include("note_definitions.jl")

using Colors, Images

brute_combine(x,y) = 1-(1-x)*(1-y)

simple_mean(x,y) = (x+y)/2

overlap(x,y) = sqrt(x*y)
overlap(x,y,z) = (x*y*z)^(1/3)

critical_bandwidth(f) = 24.7*(4.37*f/1000 + 1)

# bw is bandwidth
waveform_depression(bw) = 1/( sin( pi*min(bw/2,0.5) )^2 + max(0, bw/2 - 0.5) )

waveform(f, bandwidth) = max( 0, 1-waveform_depression(bandwidth)*sin(pi*f)^2 )

# f is reference frequency, r frequency of root note
harmonic_weight(f, r) = waveform(f/r, critical_bandwidth(f)/r)

function harmony_vis(rnote, note1, note2, note3, resolution=0.025, image_height=500)
	x_space = frequency_of.(-48:resolution:66)
	R = harmonic_weight.(x_space, note1)
	G = harmonic_weight.(x_space, note2)
	B = harmonic_weight.(x_space, note3)
	W = rnote == nothing ? ones(length(x_space)) : harmonic_weight.(x_space, rnote)
	W2 = rnote == nothing ? W : 1 .- W

	Y = overlap.(R,G)
	M = overlap.(R,B)
	C = overlap.(G,B)

	im0 = RGB.([W,W,W]...)
	im1 = RGB.([R,G,B]...)
	im2 = RGB.([ overlap.(R,max.(Y,M)), overlap.(G,max.(Y,C)), overlap.(B,max.(M,C)) ]...)
	im3 = RGB.([ overlap.(R,W), overlap.(G,W), overlap.(B,W) ]...)
	im4 = RGB.([R.*W.*brute_combine.(Y,M), G.*W.*brute_combine.(Y,C), B.*W.*brute_combine.(M,C)]...)
	
	if rnote == nothing
		H = image_height / 2
		return vcat( hcat([im1 for i in 1:H]...)', hcat([im2 for i in 1:H]...)' )
	end
	
	H = image_height / 4
	imsquared = vcat( hcat([im0 for i in 1:H]...)', hcat([im3 for i in 1:H]...)', hcat([im1 for i in 1:H]...)', hcat([im2 for i in 1:H]...)' )
	return imsquared
end