-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.jl
91 lines (65 loc) · 2.38 KB
/
index.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using Plots
using WAV
using STFT
using Ripserer
using PersistenceDiagrams
using Clustering
using Distances
function computePH(fileStr)
snd, sampFreq = wavread(fileStr)
N, _ = size(snd)
rawAmp = snd[1440000:2880000,1] # Only consider 30-second of song
# Frequency of Nth bin - n * sampFreq / window length
W = Int(sampFreq * 0.03) # Window length
w = ones(W) # Rectangular analysis window
H = 100 # Hop
L = W - H # Overlap
X = stft(rawAmp, w, L) # Analysis
s = abs2.(X) # Compute spectrogram
println("Fourier Transform complete")
#heatmap(s) # Display spectrogram
maxAmp = maximum(s) # Compute maximization
rawSoundArray = NTuple{4, Float32}[]
for t=1:length(s[1,:])
for b=1:length(s[:,1])
if s[b,t] / maxAmp > 0.025 # Exclude notes that are too insignificant
freq = b * sampFreq / W
octaveBand = log(2,freq) #Decimal Octave Band
k = floor(octaveBand) # Actual Octave Band
noteRatio = (freq - 2^k) / (2^(k+1) - 2^k) # Position in the Octave Band ie the note
# Polar Decomposition
noteX = cos(2pi * noteRatio)
noteY = sin(2pi * noteRatio)
normalizedTime = 5 * t / length(s[1,:])
v = (normalizedTime, noteX, noteY, s[b,t] / 1000)
push!(rawSoundArray, v)
end
end
end
println("Sound Array Assembled")
# Cleanup variables
rawAmp = 0
w = 0
X = 0
s = 0
# Kmedoids requires dissimilarity matrix
DissMatrix = pairwise(Euclidean(), rawSoundArray)
R = kmedoids(DissMatrix, 250)
DissMatrix = 0 # Cleanup
println("Medoids Formed")
rawSoundArray = rawSoundArray[R.medoids] # Reduce the array down to just the medoids
R = 0
# Running Persistence homology
rips = ripserer(rawSoundArray, dim_max = 2, threshold = 1, verbose=true)
println("Persistence Calculated")
println(rips)
# Ripserer outputs Inf for homology generators that never die, so we need to fix an upper bound to allow the Wasserstein metric computation
for d=1:3
for h=1:length(rips[d])
if rips[d][h][2] == Inf
rips[d][h] = PersistenceInterval(rips[d][h][1], 3)
end
end
end
return rips
end