mmfcc 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +0 -0
- data/Rakefile +1 -0
- data/bin/mmfcc +10 -0
- data/lib/mmfcc.rb +2 -0
- data/lib/mmfcc/clustering.rb +85 -0
- data/lib/mmfcc/command.rb +29 -0
- data/lib/mmfcc/mfcc.rb +148 -0
- data/lib/mmfcc/version.rb +3 -0
- data/mmfcc.gemspec +23 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c2d12ce70bab6304d063e738501344d110ebb087
|
4
|
+
data.tar.gz: df115cd944bedd7ac3d432a01346bd927909c419
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 209d10bd2cf1a88d339fe787d50ef44581e6243c5309fb767adb6d92806f5941abb3609eb28074c603493a814e41384911632ecae5cfc5603bceb8a69ab0e2e0
|
7
|
+
data.tar.gz: cc5b7b328fe53d3e039d5da16d150ddb59bda499a19ee6dcd0f1db18a3e7c7b2f96ade206811ff64d67cbde3e751852cc954df606acb4045b15354dd5ef5673c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/mmfcc
ADDED
data/lib/mmfcc.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
module Mmfcc
|
3
|
+
require "rubygems"
|
4
|
+
require "ai4r"
|
5
|
+
|
6
|
+
class Clustering
|
7
|
+
|
8
|
+
def initialize(cnum)
|
9
|
+
@cnum = cnum
|
10
|
+
end
|
11
|
+
|
12
|
+
def kmeans(all_mfcc, clusterNum)
|
13
|
+
|
14
|
+
ai4r_data = Ai4r::Data::DataSet.new(:data_items=> all_mfcc)
|
15
|
+
|
16
|
+
cluster = Ai4r::Clusterers::KMeans.new
|
17
|
+
cluster.build(ai4r_data, clusterNum)
|
18
|
+
|
19
|
+
return cluster
|
20
|
+
end
|
21
|
+
|
22
|
+
def loadMFCC(mfccFile, m, all_mfcc)
|
23
|
+
|
24
|
+
mfcc = []
|
25
|
+
mfccs = []
|
26
|
+
|
27
|
+
File.open(mfccFile, "r+b") {|f|
|
28
|
+
while line = f.read(4)
|
29
|
+
if line == "" then
|
30
|
+
break
|
31
|
+
end
|
32
|
+
|
33
|
+
val = line.unpack('f')[0]
|
34
|
+
mfcc.push(val)
|
35
|
+
|
36
|
+
|
37
|
+
if mfcc.length==m then
|
38
|
+
mfccs.push(mfcc)
|
39
|
+
all_mfcc.push(mfcc)
|
40
|
+
mfcc=[]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
}
|
44
|
+
|
45
|
+
return mfccs
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
49
|
+
|
50
|
+
mfccDir = './mfcc/'
|
51
|
+
|
52
|
+
clusterNum = @cnum.to_i
|
53
|
+
mfcc_dict = {}
|
54
|
+
all_mfcc = []
|
55
|
+
|
56
|
+
Find.find(mfccDir) {|mfccFile|
|
57
|
+
next unless mfccFile.end_with?(".mfc")
|
58
|
+
mfcc = loadMFCC(mfccFile, 20, all_mfcc)
|
59
|
+
mfcc_dict[mfccFile]=mfcc
|
60
|
+
}
|
61
|
+
|
62
|
+
cluster = kmeans(all_mfcc, clusterNum)
|
63
|
+
|
64
|
+
writeToFile = File.open("./histgram.txt",'w')
|
65
|
+
|
66
|
+
mfcc_dict.each{|key, value|
|
67
|
+
writeToFile.puts key
|
68
|
+
|
69
|
+
histgram = [0]*clusterNum
|
70
|
+
|
71
|
+
value.each{|d|
|
72
|
+
i = cluster.eval(d)
|
73
|
+
histgram[i]+=1
|
74
|
+
}
|
75
|
+
|
76
|
+
str_hist = histgram.join(" ")
|
77
|
+
writeToFile.puts str_hist
|
78
|
+
|
79
|
+
}
|
80
|
+
|
81
|
+
puts "histgram.txt is created."
|
82
|
+
writeToFile.close
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Mmfcc
|
2
|
+
require "find"
|
3
|
+
|
4
|
+
class Command
|
5
|
+
def run
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
params = ARGV.getopts('mc',"type:mp3", "m4apath:./m4a/", "mp3path:./mp3/", "cnum:8")
|
9
|
+
|
10
|
+
if params["m"] then
|
11
|
+
puts "calculating mfcc..."
|
12
|
+
|
13
|
+
require 'mmfcc/mfcc'
|
14
|
+
|
15
|
+
mfcc = Mmfcc::Mfcc.new(params["type"], params["m4apath"], params["mp3path"])
|
16
|
+
mfcc.run
|
17
|
+
end
|
18
|
+
|
19
|
+
if params["c"] then
|
20
|
+
puts "start clustering..."
|
21
|
+
|
22
|
+
require 'mmfcc/clustering'
|
23
|
+
|
24
|
+
clustering = Mmfcc::Clustering.new(params["cnum"])
|
25
|
+
clustering.run
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/mmfcc/mfcc.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
|
2
|
+
module Mmfcc
|
3
|
+
class Mfcc
|
4
|
+
|
5
|
+
def initialize(type, m4apath, mp3path)
|
6
|
+
@type = type
|
7
|
+
@m4apath = m4apath
|
8
|
+
@mp3path = mp3path
|
9
|
+
end
|
10
|
+
|
11
|
+
def m4aToRaw(m4aFile)
|
12
|
+
system("ffmpeg -i "+m4aFile+" -ab 32k -ar 16000 temp.m4a")
|
13
|
+
# decode mp3 to wav
|
14
|
+
system("ffmpeg -i temp.m4a temp.wav")
|
15
|
+
# convert wav to raw
|
16
|
+
system("sox temp.wav temp.raw")
|
17
|
+
# delete needless
|
18
|
+
system("rm temp.m4a")
|
19
|
+
system("rm temp.wav")
|
20
|
+
end
|
21
|
+
|
22
|
+
def mp3ToRaw(mp3File)
|
23
|
+
system("lame --resample 16 -b 32 -a "+mp3File+" temp.mp3")
|
24
|
+
# decode mp3 to wav
|
25
|
+
system("lame --decode temp.mp3 temp.wav")
|
26
|
+
# convert wav to raw
|
27
|
+
system("sox temp.wav temp.raw")
|
28
|
+
# delete needless
|
29
|
+
system("rm temp.mp3")
|
30
|
+
system("rm temp.wav")
|
31
|
+
end
|
32
|
+
|
33
|
+
def calcNumSample(rawFile)
|
34
|
+
# calculate byte
|
35
|
+
filesize = File.size?("temp.raw")
|
36
|
+
numsample = filesize / 2
|
37
|
+
return numsample
|
38
|
+
end
|
39
|
+
|
40
|
+
def extractCenter(inFile, outFile, period)
|
41
|
+
numsample = calcNumSample(inFile)
|
42
|
+
p numsample
|
43
|
+
|
44
|
+
fs = 16000
|
45
|
+
center = numsample / 2
|
46
|
+
start = center - fs * period
|
47
|
+
ends = center + fs * period
|
48
|
+
|
49
|
+
if start < 0 then
|
50
|
+
start = 0
|
51
|
+
end
|
52
|
+
if ends > numsample - 1 then
|
53
|
+
ends = numsample - 1
|
54
|
+
end
|
55
|
+
|
56
|
+
system("bcut +s -s "+start.to_s+" -e "+ends.to_s+" < temp.raw > "+outFile)
|
57
|
+
end
|
58
|
+
|
59
|
+
def calcMFCC(rawFile, mfccFile)
|
60
|
+
# sampling rate: 16kHz
|
61
|
+
# frame length: 400
|
62
|
+
# shift broad: 160
|
63
|
+
# num of channel: 40
|
64
|
+
# MFCC: 19 dimentions + energy
|
65
|
+
system("x2x +sf < "+rawFile+" | frame -l 400 -p 160 | mfcc -l 400 -f 16 -n 40 -m 19 -E > "+mfccFile)
|
66
|
+
end
|
67
|
+
|
68
|
+
def run
|
69
|
+
|
70
|
+
m4aDir = @m4apath
|
71
|
+
mp3Dir = @mp3path
|
72
|
+
mfccDir = './mfcc/'
|
73
|
+
rawDir = './raw/'
|
74
|
+
|
75
|
+
if not Dir::exist?(mfccDir) then
|
76
|
+
Dir::mkdir(mfccDir)
|
77
|
+
end
|
78
|
+
if not Dir::exist?(rawDir) then
|
79
|
+
Dir::mkdir(rawDir)
|
80
|
+
end
|
81
|
+
|
82
|
+
if @type == "m4a" then
|
83
|
+
|
84
|
+
if not Dir::exist?(m4aDir) then
|
85
|
+
raise "there is no directry for m4a. Please make directry ./m4a/"
|
86
|
+
end
|
87
|
+
|
88
|
+
Find.find(m4aDir) {|m4aFile|
|
89
|
+
next unless FileTest.file?(m4aFile)
|
90
|
+
next unless m4aFile.end_with?(".m4a")
|
91
|
+
|
92
|
+
mfccFile = m4aFile.sub(".m4a",".mfc")
|
93
|
+
mfccFile = mfccFile.sub(m4aDir, mfccDir)
|
94
|
+
|
95
|
+
rawFile = m4aFile.sub(".m4a",".raw")
|
96
|
+
rawFile = rawFile.sub(m4aDir, rawDir)
|
97
|
+
|
98
|
+
begin
|
99
|
+
# decode MP3
|
100
|
+
m4aToRaw(m4aFile)
|
101
|
+
|
102
|
+
# convert 30s mp3 to rawFile
|
103
|
+
extractCenter("temp.raw", rawFile, 15)
|
104
|
+
|
105
|
+
calcMFCC(rawFile, mfccFile)
|
106
|
+
|
107
|
+
system("rm temp.raw")
|
108
|
+
rescue
|
109
|
+
next
|
110
|
+
puts "failed at decode m4a"
|
111
|
+
end
|
112
|
+
}
|
113
|
+
else
|
114
|
+
|
115
|
+
if not Dir::exist?(mp3Dir) then
|
116
|
+
raise "there is no directry for mp3. Please make directry ./mp3/"
|
117
|
+
end
|
118
|
+
|
119
|
+
Find.find(mp3Dir) {|mp3File|
|
120
|
+
next unless FileTest.file?(mp3File)
|
121
|
+
next unless mp3File.end_with?(".mp3")
|
122
|
+
|
123
|
+
mfccFile = mp3File.sub(".mp3",".mfc")
|
124
|
+
mfccFile = mfccFile.sub(mp3Dir, mfccDir)
|
125
|
+
|
126
|
+
rawFile = mp3File.sub(".mp3",".raw")
|
127
|
+
rawFile = rawFile.sub(mp3Dir, rawDir)
|
128
|
+
|
129
|
+
begin
|
130
|
+
# decode MP3
|
131
|
+
mp3ToRaw(mp3File)
|
132
|
+
|
133
|
+
# convert 30s mp3 to rawFile
|
134
|
+
extractCenter("temp.raw", rawFile, 15)
|
135
|
+
|
136
|
+
calcMFCC(rawFile, mfccFile)
|
137
|
+
|
138
|
+
system("rm temp.raw")
|
139
|
+
rescue
|
140
|
+
next
|
141
|
+
puts "failed at decode mp3"
|
142
|
+
end
|
143
|
+
}
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
data/mmfcc.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "mmfcc/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "mmfcc"
|
7
|
+
s.version = Mmfcc::VERSION
|
8
|
+
s.authors = ["RittaNarita"]
|
9
|
+
s.email = ["narittan@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/RittaNarita/Mmfcc"
|
11
|
+
s.summary = %q{the tool for making mfcc of songs}
|
12
|
+
s.description = %q{you can make the Mel-frequency cepstrum, which is a feature spectrum of a song. }
|
13
|
+
s.license = "GPLv2"
|
14
|
+
s.rubyforge_project = "mmfcc"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "ai4r", '~> 0'
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mmfcc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- RittaNarita
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ai4r
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: 'you can make the Mel-frequency cepstrum, which is a feature spectrum
|
28
|
+
of a song. '
|
29
|
+
email:
|
30
|
+
- narittan@gmail.com
|
31
|
+
executables:
|
32
|
+
- mmfcc
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- ".gitignore"
|
37
|
+
- Gemfile
|
38
|
+
- README.md
|
39
|
+
- Rakefile
|
40
|
+
- bin/mmfcc
|
41
|
+
- lib/mmfcc.rb
|
42
|
+
- lib/mmfcc/clustering.rb
|
43
|
+
- lib/mmfcc/command.rb
|
44
|
+
- lib/mmfcc/mfcc.rb
|
45
|
+
- lib/mmfcc/version.rb
|
46
|
+
- mmfcc.gemspec
|
47
|
+
homepage: https://github.com/RittaNarita/Mmfcc
|
48
|
+
licenses:
|
49
|
+
- GPLv2
|
50
|
+
metadata: {}
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project: mmfcc
|
67
|
+
rubygems_version: 2.2.0
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: the tool for making mfcc of songs
|
71
|
+
test_files: []
|