noyes 0.6.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -2
- data/VERSION +1 -0
- data/bin/mock_noyes_server +27 -0
- data/bin/nrec +80 -21
- data/lib/c_impl/discrete_cosine_transform.c +60 -0
- data/lib/c_impl/extconf.rb +2 -0
- data/lib/c_impl/fast_8k_mfcc.c +39 -0
- data/lib/c_impl/hamming_window.c +41 -0
- data/lib/c_impl/live_cmn.c +49 -0
- data/lib/c_impl/log_compressor.c +43 -0
- data/lib/c_impl/mel_filter.c +115 -0
- data/lib/c_impl/n_dft.c +63 -0
- data/lib/c_impl/n_discrete_cosine_transform.c +46 -0
- data/lib/c_impl/n_fast_8k_mfcc.c +55 -0
- data/lib/c_impl/n_hamming_window.c +30 -0
- data/lib/c_impl/n_live_cmn.c +72 -0
- data/lib/c_impl/n_log_compressor.c +21 -0
- data/lib/c_impl/n_matrix.c +40 -0
- data/lib/c_impl/n_mel_filter.c +152 -0
- data/lib/c_impl/n_power_spec.c +27 -0
- data/lib/c_impl/n_preemphasis.c +25 -0
- data/lib/c_impl/n_segmenter.c +61 -0
- data/lib/c_impl/noyes.h +151 -0
- data/lib/c_impl/noyes_c.c +88 -0
- data/lib/c_impl/power_spectrum.c +42 -0
- data/lib/c_impl/preemphasis.c +43 -0
- data/lib/c_impl/rnoyes.h +17 -0
- data/lib/c_impl/segmenter.c +48 -0
- data/lib/common/file2pcm.rb +9 -0
- data/lib/common/mock_noyes_server.rb +102 -0
- data/lib/common/noyes_protocol.rb +10 -0
- data/lib/common/send_incrementally.rb +48 -23
- data/lib/common.rb +1 -0
- data/lib/noyes_c.rb +2 -0
- data/ship/noyes.jar +0 -0
- metadata +45 -6
data/README
CHANGED
@@ -2,8 +2,8 @@ Noyes is a signal processing library. It currently has just enough signal
|
|
2
2
|
processing to produce features suitable for speech recognition.
|
3
3
|
|
4
4
|
Pronunciation: Typically pronounced the same as 'noise'. But "NO!... YES!" is
|
5
|
-
considered acceptable if you
|
6
|
-
|
5
|
+
considered acceptable if you say it with sufficient conviction to make people
|
6
|
+
think you have truly changed your mind.
|
7
7
|
|
8
8
|
Noyes is a general purpose signal processing tool that is flexible enough for
|
9
9
|
many purposes. However, it exists because there is a need for low-latency high
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.8.0
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: set filetype=ruby :
|
3
|
+
ROOT = File.dirname(File.dirname(__FILE__))
|
4
|
+
$: << "#{ROOT}/lib/common"
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require 'ostruct'
|
8
|
+
require 'mock_noyes_server'
|
9
|
+
DEF_PORT = 24902
|
10
|
+
options = OpenStruct.new
|
11
|
+
options.port = DEF_PORT
|
12
|
+
OptionParser.new do |opt|
|
13
|
+
opt.banner = 'Usage: mock_nserv [options]'
|
14
|
+
opt.on '-v', '--verbose', 'Output more information' do
|
15
|
+
options[:verbose] = true
|
16
|
+
end
|
17
|
+
opt.on '-h', '--help', 'Display this screen' do
|
18
|
+
puts opt
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
opt.on '-p', '--port [PORT]', "Port (Default is #{DEF_PORT})" do |port|
|
22
|
+
options.port = port
|
23
|
+
end
|
24
|
+
end.parse!
|
25
|
+
|
26
|
+
server = MockNoyesServer.new options
|
27
|
+
server.run
|
data/bin/nrec
CHANGED
@@ -1,34 +1,84 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# vim: set filetype=ruby :
|
3
3
|
ROOT = File.dirname(File.dirname(__FILE__))
|
4
|
+
VERSION_FILE = "#{ROOT}/VERSION"
|
4
5
|
$: << "#{ROOT}/lib" << "#{ROOT}/ship"
|
5
6
|
|
6
|
-
require '
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
require 'trollop'
|
8
|
+
|
9
|
+
options = Trollop::options do
|
10
|
+
version "Noyes #{IO.read(VERSION_FILE).strip} (c) 2010 Talkhouse"
|
11
|
+
banner 'Usage: nrec [options] file1 file2 ...'
|
12
|
+
opt :implementation, "ruby, c, or java", :default => 'ruby'
|
13
|
+
opt :address, "address", :default => '174.129.244.159'
|
14
|
+
opt :port, "port", :default => 2348
|
15
|
+
opt :bits, "bit depth", :default => 16
|
16
|
+
opt :frequency, "sampling frequency", :default => 16000
|
17
|
+
opt :payload, "mfcc, or pcm", :default => 'mfcc'
|
18
|
+
opt :verbose, "verbose", :default => false
|
19
|
+
end
|
20
|
+
|
21
|
+
if options[:bits] != 16 && options[:payload] == 'mfcc'
|
22
|
+
Trollop::die :bits, "must be 16 for mfcc"
|
23
|
+
end
|
24
|
+
|
25
|
+
if options[:payload] == 'mfcc' && ((options[:frequency] % 8000) != 0)
|
26
|
+
Trollop::die :frequency, "(#{options[:frequency]}) for mfcc must be divisible by 8000"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Must set implementation specific library path before requiring libraries.
|
30
|
+
case options[:implementation].to_sym
|
31
|
+
when :fastc
|
32
|
+
if RUBY_PLATFORM == 'java'
|
33
|
+
puts "The Java implementation is not accessable from Ruby, only JRuby."
|
34
|
+
puts "You'll need to check your environment carefully. If you've"
|
35
|
+
puts "installed this gem under both ruby and jruby and both are in"
|
36
|
+
puts "your current environment you may have created a conflict."
|
37
|
+
puts "You must make sure the Ruby path preceeds the JRuby path."
|
38
|
+
exit
|
12
39
|
end
|
13
|
-
options[:
|
14
|
-
|
15
|
-
|
40
|
+
puts "Using Fast C implementation" if options[:verbose]
|
41
|
+
require 'noyes_c'
|
42
|
+
include NoyesC
|
43
|
+
def send_incremental_features file, to_server, from_server, bits, freq
|
44
|
+
puts "bits and freq #{bits} #{freq}"
|
45
|
+
feature_maker = NoyesC::Fast8kMfcc.new
|
46
|
+
pcm = file2pcm file, bits, freq
|
47
|
+
to_server.write TMAGIC
|
48
|
+
to_server.write TSTART
|
49
|
+
pcm.each_slice 1230 do |data|
|
50
|
+
data >>= feature_maker
|
51
|
+
next unless data
|
52
|
+
to_server.write TCEPSTRA
|
53
|
+
to_server.write [data.size].pack('N')
|
54
|
+
print '.'
|
55
|
+
data.each {|cmn| to_server.write cmn.pack('g*')}
|
56
|
+
to_server.flush
|
57
|
+
end
|
58
|
+
to_server.write TEND
|
59
|
+
to_server.write TBYE
|
60
|
+
to_server.flush
|
61
|
+
from_server.read
|
16
62
|
end
|
17
|
-
|
18
|
-
|
63
|
+
when :c
|
64
|
+
if RUBY_PLATFORM == 'java'
|
65
|
+
puts "The Java implementation is not accessable from Ruby, only JRuby."
|
66
|
+
puts "You'll need to check your environment carefully. If you've"
|
67
|
+
puts "installed this gem under both ruby and jruby and both are in"
|
68
|
+
puts "your current environment you may have created a conflict."
|
69
|
+
puts "You must make sure the Ruby path preceeds the JRuby path."
|
19
70
|
exit
|
20
71
|
end
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
case options[:implementation]
|
72
|
+
puts "Using C implementation" if options[:verbose]
|
73
|
+
require 'noyes_c'
|
74
|
+
include NoyesC
|
25
75
|
when :java
|
26
76
|
if RUBY_PLATFORM != 'java'
|
27
77
|
puts "The Java implementation is not accessable from Ruby, only JRuby."
|
28
78
|
puts "You'll need to check your environment carefully. If you've"
|
29
79
|
puts "installed this gem under both ruby and jruby and both are in"
|
30
80
|
puts "your current environment you may have created a conflict."
|
31
|
-
puts "
|
81
|
+
puts "You must make sure the JRuby path preceeds the Ruby path."
|
32
82
|
exit
|
33
83
|
end
|
34
84
|
puts "Using Java implementation" if options[:verbose]
|
@@ -48,14 +98,23 @@ when :ruby
|
|
48
98
|
end
|
49
99
|
require 'socket'
|
50
100
|
|
51
|
-
def recognize file,
|
52
|
-
TCPSocket.open(
|
53
|
-
|
101
|
+
def recognize file, options
|
102
|
+
TCPSocket.open(options[:address], options[:port]) do |client|
|
103
|
+
bits, rate = options[:bits], options[:frequency]
|
104
|
+
if options[:pcm]
|
105
|
+
send_incremental_pcm file, client, client, bits, rate
|
106
|
+
else
|
107
|
+
send_incremental_features file, client, client, bits, rate
|
108
|
+
end
|
54
109
|
end
|
55
110
|
end
|
56
111
|
|
57
112
|
ARGV.each do |file|
|
58
113
|
puts "recognizing file #{file}" if options[:verbose]
|
59
|
-
result = recognize file
|
60
|
-
|
114
|
+
result = recognize file, options
|
115
|
+
if options[:verbose]
|
116
|
+
puts "\n#{result}"
|
117
|
+
else
|
118
|
+
puts "\n#{result[:transcript]}"
|
119
|
+
end
|
61
120
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "noyes.h"
|
3
|
+
#include "rnoyes.h"
|
4
|
+
|
5
|
+
static int id_push;
|
6
|
+
|
7
|
+
VALUE cDiscreteCosineTransform;
|
8
|
+
|
9
|
+
static void dct_free(void *p) {
|
10
|
+
free_dct(p);
|
11
|
+
}
|
12
|
+
|
13
|
+
static VALUE t_init(VALUE self, VALUE args) {
|
14
|
+
int len = RARRAY_LEN(args);
|
15
|
+
int rows=13,cols=32;
|
16
|
+
if (len > 0)
|
17
|
+
rows = NUM2INT(rb_ary_entry(args, 0));
|
18
|
+
if (len > 1)
|
19
|
+
cols = NUM2INT(rb_ary_entry(args, 1));
|
20
|
+
|
21
|
+
DiscreteCosineTransform *dct = new_dct(rows,cols);
|
22
|
+
VALUE dctv = Data_Wrap_Struct(cDiscreteCosineTransform, 0, dct_free, dct);
|
23
|
+
rb_iv_set(self, "@dct", dctv);
|
24
|
+
return self;
|
25
|
+
}
|
26
|
+
|
27
|
+
static VALUE t_left_shift(VALUE self, VALUE obj) {
|
28
|
+
NMatrix *M = v_2_nmatrix(obj);
|
29
|
+
DiscreteCosineTransform *dct;
|
30
|
+
VALUE dctv = rb_iv_get(self, "@dct");
|
31
|
+
Data_Get_Struct(dctv, DiscreteCosineTransform, dct);
|
32
|
+
NMatrix *N = dct_apply(dct, M);
|
33
|
+
VALUE result = nmatrix_2_v(N);
|
34
|
+
free_nmatrix(N);
|
35
|
+
return result;
|
36
|
+
}
|
37
|
+
|
38
|
+
static VALUE t_melcos(VALUE self) {
|
39
|
+
DiscreteCosineTransform *dct;
|
40
|
+
VALUE dctv = rb_iv_get(self, "@dct");
|
41
|
+
Data_Get_Struct(dctv, DiscreteCosineTransform, dct);
|
42
|
+
NMatrix *N = new_nmatrix(dct->rows, dct->cols);
|
43
|
+
int i;
|
44
|
+
for (i=0;i<dct->rows;++i) {
|
45
|
+
memcpy(N->data[i],dct->melcos[i], dct->cols * sizeof(double));
|
46
|
+
}
|
47
|
+
VALUE result = nmatrix_2_v(N);
|
48
|
+
free_nmatrix(N);
|
49
|
+
return result;
|
50
|
+
}
|
51
|
+
|
52
|
+
void Init_dct() {
|
53
|
+
VALUE m_noyes_c = rb_define_module("NoyesC");
|
54
|
+
cDiscreteCosineTransform = rb_define_class_under(m_noyes_c,
|
55
|
+
"DCT", rb_cObject);
|
56
|
+
rb_define_method(cDiscreteCosineTransform, "initialize", t_init, -2);
|
57
|
+
rb_define_method(cDiscreteCosineTransform, "<<", t_left_shift, 1);
|
58
|
+
rb_define_method(cDiscreteCosineTransform, "melcos", t_melcos, 0);
|
59
|
+
id_push = rb_intern("push");
|
60
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "noyes.h"
|
3
|
+
#include "rnoyes.h"
|
4
|
+
|
5
|
+
static int id_push;
|
6
|
+
|
7
|
+
VALUE cFast8kMfcc;
|
8
|
+
|
9
|
+
static void fast_8k_mfcc_free(Fast8kMfcc *p) {
|
10
|
+
free_fast_8k_mfcc(p);
|
11
|
+
}
|
12
|
+
|
13
|
+
static VALUE t_init(VALUE self, VALUE args) {
|
14
|
+
Fast8kMfcc *s = new_fast_8k_mfcc();
|
15
|
+
VALUE fast_8k_mfcc = Data_Wrap_Struct(cFast8kMfcc, 0, fast_8k_mfcc_free, s);
|
16
|
+
rb_iv_set(self, "@fast_8k_mfcc", fast_8k_mfcc);
|
17
|
+
|
18
|
+
return self;
|
19
|
+
}
|
20
|
+
|
21
|
+
static VALUE t_left_shift(VALUE self, VALUE obj) {
|
22
|
+
NMatrix1 *M = v_2_nmatrix1(obj);
|
23
|
+
VALUE fast_8k_mfcc = rb_iv_get(self, "@fast_8k_mfcc");
|
24
|
+
Fast8kMfcc *s;
|
25
|
+
Data_Get_Struct(fast_8k_mfcc, Fast8kMfcc, s);
|
26
|
+
NMatrix *N = fast_8k_mfcc_apply(s, M);
|
27
|
+
VALUE result = nmatrix_2_v(N);
|
28
|
+
free_nmatrix(N);
|
29
|
+
free_nmatrix1(M);
|
30
|
+
return result;
|
31
|
+
}
|
32
|
+
|
33
|
+
void Init_fast_8k_mfcc() {
|
34
|
+
VALUE m_noyes_c = rb_define_module("NoyesC");
|
35
|
+
cFast8kMfcc = rb_define_class_under(m_noyes_c, "Fast8kMfcc", rb_cObject);
|
36
|
+
rb_define_method(cFast8kMfcc, "initialize", t_init, -2);
|
37
|
+
rb_define_method(cFast8kMfcc, "<<", t_left_shift, 1);
|
38
|
+
id_push = rb_intern("push");
|
39
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "noyes.h"
|
3
|
+
#include "rnoyes.h"
|
4
|
+
|
5
|
+
static int id_push;
|
6
|
+
|
7
|
+
VALUE cHammingWindow;
|
8
|
+
|
9
|
+
static void hamming_window_free(void *p) {
|
10
|
+
free_hamming_window(p);
|
11
|
+
}
|
12
|
+
static VALUE t_init(VALUE self, VALUE args) {
|
13
|
+
int len = RARRAY_LEN(args);
|
14
|
+
int winsz = 205;
|
15
|
+
if (len > 0) {
|
16
|
+
winsz = NUM2INT(rb_ary_entry(args, 0));
|
17
|
+
}
|
18
|
+
HammingWindow *hw = new_hamming_window(winsz);
|
19
|
+
VALUE hwv = Data_Wrap_Struct(cHammingWindow, 0, hamming_window_free, hw);
|
20
|
+
rb_iv_set(self, "@hw", hwv);
|
21
|
+
return self;
|
22
|
+
}
|
23
|
+
|
24
|
+
static VALUE t_left_shift(VALUE self, VALUE obj) {
|
25
|
+
NMatrix *M = v_2_nmatrix(obj);
|
26
|
+
HammingWindow *hw;
|
27
|
+
VALUE hwv = rb_iv_get(self, "@hw");
|
28
|
+
Data_Get_Struct(hwv, HammingWindow, hw);
|
29
|
+
NMatrix *N = hamming_window_apply(hw, M);
|
30
|
+
VALUE result = nmatrix_2_v(N);
|
31
|
+
free_nmatrix(N);
|
32
|
+
return result;
|
33
|
+
}
|
34
|
+
|
35
|
+
void Init_hamming_window() {
|
36
|
+
VALUE m_noyes_c = rb_define_module("NoyesC");
|
37
|
+
cHammingWindow = rb_define_class_under(m_noyes_c, "HammingWindow", rb_cObject);
|
38
|
+
rb_define_method(cHammingWindow, "initialize", t_init, -2);
|
39
|
+
rb_define_method(cHammingWindow, "<<", t_left_shift, 1);
|
40
|
+
id_push = rb_intern("push");
|
41
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "noyes.h"
|
3
|
+
#include "rnoyes.h"
|
4
|
+
|
5
|
+
static int id_push;
|
6
|
+
|
7
|
+
VALUE cLiveCMN;
|
8
|
+
|
9
|
+
static void live_cmn_free(void *p) {
|
10
|
+
free_live_cmn(p);
|
11
|
+
}
|
12
|
+
|
13
|
+
static VALUE t_init(VALUE self, VALUE args) {
|
14
|
+
int dimensions=13, init_mean=45.0, window_size=100, shift=160;
|
15
|
+
int len = RARRAY_LEN(args);
|
16
|
+
if (len > 0)
|
17
|
+
dimensions = NUM2INT(rb_ary_entry(args, 0));
|
18
|
+
if (len > 1)
|
19
|
+
init_mean= NUM2INT(rb_ary_entry(args, 1));
|
20
|
+
if (len > 2)
|
21
|
+
window_size = NUM2INT(rb_ary_entry(args, 2));
|
22
|
+
if (len > 3)
|
23
|
+
shift = NUM2INT(rb_ary_entry(args, 3));
|
24
|
+
|
25
|
+
LiveCMN *cmn = new_live_cmn(dimensions, init_mean, window_size, shift);
|
26
|
+
VALUE cmnv = Data_Wrap_Struct(cLiveCMN, 0, live_cmn_free, cmn);
|
27
|
+
rb_iv_set(self, "@cmn", cmnv);
|
28
|
+
return self;
|
29
|
+
}
|
30
|
+
|
31
|
+
static VALUE t_left_shift(VALUE self, VALUE obj) {
|
32
|
+
NMatrix *M = v_2_nmatrix(obj);
|
33
|
+
LiveCMN *cmn;
|
34
|
+
VALUE cmnv = rb_iv_get(self, "@cmn");
|
35
|
+
Data_Get_Struct(cmnv, LiveCMN, cmn);
|
36
|
+
NMatrix *N = live_cmn_apply(cmn, M);
|
37
|
+
VALUE result = nmatrix_2_v(N);
|
38
|
+
free_nmatrix(N);
|
39
|
+
return result;
|
40
|
+
}
|
41
|
+
|
42
|
+
void Init_live_cmn() {
|
43
|
+
VALUE m_noyes_c = rb_define_module("NoyesC");
|
44
|
+
cLiveCMN = rb_define_class_under(m_noyes_c, "LiveCMN", rb_cObject);
|
45
|
+
rb_define_method(cLiveCMN, "initialize", t_init, -2);
|
46
|
+
rb_define_method(cLiveCMN, "<<", t_left_shift, 1);
|
47
|
+
id_push = rb_intern("push");
|
48
|
+
}
|
49
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "noyes.h"
|
3
|
+
#include "rnoyes.h"
|
4
|
+
|
5
|
+
static int id_push;
|
6
|
+
|
7
|
+
VALUE cLogCompressor;
|
8
|
+
|
9
|
+
static void log_compressor_free(void *p) {
|
10
|
+
free_log_compressor(p);
|
11
|
+
}
|
12
|
+
|
13
|
+
static VALUE t_init(VALUE self, VALUE args) {
|
14
|
+
int len = RARRAY_LEN(args);
|
15
|
+
double log_zero = -0.00001;
|
16
|
+
if (len > 0) {
|
17
|
+
log_zero = NUM2DBL(rb_ary_entry(args, 0));
|
18
|
+
}
|
19
|
+
LogCompressor *lc = new_log_compressor(log_zero);
|
20
|
+
VALUE lcv = Data_Wrap_Struct(cLogCompressor, 0, log_compressor_free, lc);
|
21
|
+
rb_iv_set(self, "@log_compressor", lcv);
|
22
|
+
return self;
|
23
|
+
}
|
24
|
+
|
25
|
+
static VALUE t_left_shift(VALUE self, VALUE obj) {
|
26
|
+
NMatrix *M = v_2_nmatrix(obj);
|
27
|
+
LogCompressor *lc;
|
28
|
+
VALUE lcv = rb_iv_get(self, "@log_compressor");
|
29
|
+
Data_Get_Struct(lcv, LogCompressor, lc);
|
30
|
+
NMatrix *N = log_compressor_apply(lc, M);
|
31
|
+
VALUE result = nmatrix_2_v(N);
|
32
|
+
free_nmatrix(N);
|
33
|
+
free_nmatrix(M);
|
34
|
+
return result;
|
35
|
+
}
|
36
|
+
|
37
|
+
void Init_log_compressor() {
|
38
|
+
VALUE m_noyes_c = rb_define_module("NoyesC");
|
39
|
+
cLogCompressor = rb_define_class_under(m_noyes_c, "LogCompressor", rb_cObject);
|
40
|
+
rb_define_method(cLogCompressor, "initialize", t_init, -2);
|
41
|
+
rb_define_method(cLogCompressor, "<<", t_left_shift, 1);
|
42
|
+
id_push = rb_intern("push");
|
43
|
+
}
|
@@ -0,0 +1,115 @@
|
|
1
|
+
#include "noyes.h"
|
2
|
+
#include "rnoyes.h"
|
3
|
+
#include "math.h"
|
4
|
+
|
5
|
+
static int id_push;
|
6
|
+
|
7
|
+
VALUE cMelFilter;
|
8
|
+
|
9
|
+
static void mel_filter_free(void *p) {
|
10
|
+
free_mel_filter(p);
|
11
|
+
}
|
12
|
+
|
13
|
+
static VALUE t_make_filter(VALUE self, VALUE(left), VALUE(center), VALUE(right), VALUE(init_freq), VALUE(delta)) {
|
14
|
+
NMatrix1 *d = make_filter(NUM2DBL(left), NUM2DBL(center),
|
15
|
+
NUM2DBL(right), NUM2DBL(init_freq), NUM2DBL(delta));
|
16
|
+
if (d) {
|
17
|
+
VALUE result = rb_ary_new2(2);
|
18
|
+
rb_ary_store(result, 0, INT2FIX(round(d->data[0])));
|
19
|
+
int i;
|
20
|
+
VALUE filt = rb_ary_new2(d->rows-1);
|
21
|
+
for (i=1;i<d->rows;++i) {
|
22
|
+
rb_ary_store(filt, i-1, rb_float_new(d->data[i]));
|
23
|
+
}
|
24
|
+
rb_ary_store(result, 1, filt);
|
25
|
+
free_nmatrix1(d);
|
26
|
+
return result;
|
27
|
+
}
|
28
|
+
return Qnil;
|
29
|
+
}
|
30
|
+
|
31
|
+
static VALUE t_to_mel(VALUE self, VALUE m) {
|
32
|
+
return rb_float_new(mel(NUM2DBL(m)));
|
33
|
+
}
|
34
|
+
|
35
|
+
static VALUE t_to_linear(VALUE self, VALUE f) {
|
36
|
+
return rb_float_new(melinv(NUM2DBL(f)));
|
37
|
+
}
|
38
|
+
|
39
|
+
static VALUE t_make_bank_parameters(VALUE self, VALUE srate, VALUE nfft,
|
40
|
+
VALUE nfilt, VALUE lowerf, VALUE upperf) {
|
41
|
+
NMatrix *d = make_bank_parameters(NUM2INT(srate), NUM2INT(nfft),
|
42
|
+
NUM2INT(nfilt), NUM2INT(lowerf), NUM2INT(upperf));
|
43
|
+
if (d) {
|
44
|
+
VALUE result = rb_ary_new2(d->rows);
|
45
|
+
int i,j;
|
46
|
+
for (i=0;i<d->rows;++i) {
|
47
|
+
VALUE row = rb_ary_new2(d->cols);
|
48
|
+
rb_ary_store(result, i, row);
|
49
|
+
for (j=0;j<d->cols;++j) {
|
50
|
+
rb_ary_store(row, j, rb_float_new(d->data[i][j]));
|
51
|
+
}
|
52
|
+
}
|
53
|
+
free_nmatrix(d);
|
54
|
+
return result;
|
55
|
+
}
|
56
|
+
return Qnil;
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE t_init(VALUE self, VALUE args) {
|
60
|
+
int srate=8000, nfft=256, nfilt=32, lowerf=200, upperf=3700;
|
61
|
+
int len = RARRAY_LEN(args);
|
62
|
+
if (len > 0)
|
63
|
+
srate = NUM2INT(rb_ary_entry(args, 0));
|
64
|
+
if (len > 1)
|
65
|
+
nfft = NUM2INT(rb_ary_entry(args, 1));
|
66
|
+
if (len > 2)
|
67
|
+
nfilt = NUM2INT(rb_ary_entry(args, 2));
|
68
|
+
if (len > 3)
|
69
|
+
lowerf = NUM2INT(rb_ary_entry(args, 3));
|
70
|
+
if (len > 4)
|
71
|
+
upperf = NUM2INT(rb_ary_entry(args, 4));
|
72
|
+
|
73
|
+
MelFilter *s = new_mel_filter(srate, nfft, nfilt, lowerf, upperf);
|
74
|
+
VALUE mel_filter = Data_Wrap_Struct(cMelFilter, 0, mel_filter_free, s);
|
75
|
+
rb_iv_set(self, "@mel_filter", mel_filter);
|
76
|
+
|
77
|
+
return self;
|
78
|
+
}
|
79
|
+
|
80
|
+
static VALUE t_left_shift(VALUE self, VALUE obj) {
|
81
|
+
NMatrix *M = v_2_nmatrix(obj);
|
82
|
+
VALUE mel_filter = rb_iv_get(self, "@mel_filter");
|
83
|
+
MelFilter *s;
|
84
|
+
Data_Get_Struct(mel_filter, MelFilter, s);
|
85
|
+
NMatrix *d = mel_filter_apply(s, M);
|
86
|
+
|
87
|
+
if (d) {
|
88
|
+
VALUE result = rb_ary_new2(d->rows);
|
89
|
+
int i,j;
|
90
|
+
for (i=0;i<d->rows;++i) {
|
91
|
+
VALUE row = rb_ary_new2(d->cols);
|
92
|
+
rb_ary_store(result, i, row);
|
93
|
+
for (j=0;j<d->cols;++j) {
|
94
|
+
rb_ary_store(row, j, rb_float_new(d->data[i][j]));
|
95
|
+
}
|
96
|
+
}
|
97
|
+
free_nmatrix(d);
|
98
|
+
return result;
|
99
|
+
}
|
100
|
+
return Qnil;
|
101
|
+
}
|
102
|
+
|
103
|
+
|
104
|
+
void Init_mel_filter() {
|
105
|
+
VALUE m_noyes_c = rb_define_module("NoyesC");
|
106
|
+
cMelFilter = rb_define_class_under(m_noyes_c, "MelFilter", rb_cObject);
|
107
|
+
rb_define_method(cMelFilter, "initialize", t_init, -2);
|
108
|
+
rb_define_method(cMelFilter, "<<", t_left_shift, 1);
|
109
|
+
rb_define_module_function(cMelFilter, "make_bank_parameters", t_make_bank_parameters, 5);
|
110
|
+
rb_define_module_function(cMelFilter, "make_filter", t_make_filter, 5);
|
111
|
+
rb_define_module_function(cMelFilter, "to_linear", t_to_linear, 1);
|
112
|
+
rb_define_module_function(cMelFilter, "to_mel", t_to_mel, 1);
|
113
|
+
id_push = rb_intern("push");
|
114
|
+
}
|
115
|
+
|
data/lib/c_impl/n_dft.c
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#include "noyes.h"
|
2
|
+
#include "stdlib.h"
|
3
|
+
#include "memory.h"
|
4
|
+
#include "math.h"
|
5
|
+
#include "stdio.h"
|
6
|
+
|
7
|
+
NMatrix * dft(double * data, int datalen, int size) {
|
8
|
+
if (datalen> size) {
|
9
|
+
fprintf(stderr,"Size(%d) must be larger than data length(%d)", size, datalen);
|
10
|
+
return NULL;
|
11
|
+
}
|
12
|
+
NMatrix *M = new_nmatrix(2, size);
|
13
|
+
double * real = M->data[0];
|
14
|
+
double * imag = M->data[1];
|
15
|
+
int j=0,i;
|
16
|
+
for (i=0;i<size;++i) {
|
17
|
+
imag[i] = 0.0;
|
18
|
+
real[i] = 0.0;
|
19
|
+
}
|
20
|
+
memcpy(real, data, datalen * sizeof(double));
|
21
|
+
|
22
|
+
for (i=0;i<size;++i) {
|
23
|
+
if (i < j) {
|
24
|
+
double temp = real[j];
|
25
|
+
real[j] = real[i];
|
26
|
+
real[i] = temp;
|
27
|
+
temp = imag[j];
|
28
|
+
imag[j] = imag[i];
|
29
|
+
imag[i] = temp;
|
30
|
+
}
|
31
|
+
int m = size/2;
|
32
|
+
while (j>=m && m> 1) {
|
33
|
+
j -= m;
|
34
|
+
m /= 2;
|
35
|
+
}
|
36
|
+
j+=m;
|
37
|
+
}
|
38
|
+
int k=1,m;
|
39
|
+
while (k < size) {
|
40
|
+
int incr = 2*k;
|
41
|
+
double mul_r = cos(M_PI/k);
|
42
|
+
double mul_i = sin(M_PI/k);
|
43
|
+
double w_r = 1;
|
44
|
+
double w_i = 0;
|
45
|
+
for (i=0;i<k;++i) {
|
46
|
+
for (m=i;m<size; m+=incr) {
|
47
|
+
double tmp_r = w_r * real[m+k] - w_i * imag[m+k];
|
48
|
+
double tmp_i = w_r * imag[m+k] + w_i * real[m+k];
|
49
|
+
real[m+k] = real[m] - tmp_r;
|
50
|
+
imag[m+k] = imag[m] - tmp_i;
|
51
|
+
real[m] = real[m] + tmp_r;
|
52
|
+
imag[m] = imag[m] + tmp_i;
|
53
|
+
}
|
54
|
+
double tmp_r = w_r * mul_r - w_i * mul_i;
|
55
|
+
double tmp_i = w_r * mul_i + w_i * mul_r;
|
56
|
+
w_r = tmp_r;
|
57
|
+
w_i = tmp_i;
|
58
|
+
}
|
59
|
+
k=incr;
|
60
|
+
}
|
61
|
+
|
62
|
+
return M;
|
63
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#include "noyes.h"
|
2
|
+
#include "math.h"
|
3
|
+
|
4
|
+
DiscreteCosineTransform * new_dct(int rows, int cols) {
|
5
|
+
DiscreteCosineTransform *dct = malloc(sizeof(DiscreteCosineTransform));
|
6
|
+
dct->melcos = malloc(rows *sizeof(double*));
|
7
|
+
dct->rows = rows;
|
8
|
+
dct->cols = cols;
|
9
|
+
int i,j;
|
10
|
+
for (i=0;i<rows;++i) {
|
11
|
+
double freq = M_PI * i / cols;
|
12
|
+
double * ldct = malloc(sizeof(double) * cols);
|
13
|
+
for (j=0;j<cols;++j) {
|
14
|
+
ldct[j] = cos(freq * (j + 0.5)) / rows;
|
15
|
+
}
|
16
|
+
dct->melcos[i] = ldct;
|
17
|
+
}
|
18
|
+
return dct;
|
19
|
+
}
|
20
|
+
|
21
|
+
void free_dct(DiscreteCosineTransform *dct) {
|
22
|
+
int i;
|
23
|
+
for (i=0;i<dct->rows;++i) {
|
24
|
+
free(dct->melcos[i]);
|
25
|
+
}
|
26
|
+
free(dct->melcos);
|
27
|
+
free(dct);
|
28
|
+
}
|
29
|
+
|
30
|
+
NMatrix * dct_apply(DiscreteCosineTransform *self, NMatrix *data) {
|
31
|
+
NMatrix *M = new_nmatrix(data->rows, self->rows);
|
32
|
+
int i,j,k;
|
33
|
+
for (i=0;i<M->rows;++i) {
|
34
|
+
for (j=0;j<M->cols;++j) {
|
35
|
+
M->data[i][j] = 0;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
for (i=0;i<data->rows;++i) {
|
39
|
+
for (j=0;j<self->rows;++j) {
|
40
|
+
for (k=0;k<self->cols; ++k) {
|
41
|
+
M->data[i][j] += data->data[i][k] * self->melcos[j][k];
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
return M;
|
46
|
+
}
|