noyes 0.6.1 → 0.8.0
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.
- 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
|
+
}
|