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 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 yell it loudly enough or at least with sufficient
6
- conviction to make people think you have truly changed your mind.
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 'optparse'
7
- options = {}
8
- OptionParser.new do |opt|
9
- opt.banner = 'Usage: nrec [options] file1 file2 ...'
10
- opt.on '-v', '--verbose', 'Output more information' do
11
- options[:verbose] = true
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[:implementation] = :ruby
14
- opt.on '-j', '--java', 'Use java implementation' do
15
- options[:implementation] = :java
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
- opt.on( '-h', '--help', 'Display this screen' ) do
18
- puts opt
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
- end.parse!
22
-
23
- # Must set implementation specific library path before requiring libraries.
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 "you must make sure the jruby path preceeds the ruby path."
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, node='174.129.244.159', port=2348
52
- TCPSocket.open(node, port) do |client|
53
- send_incremental_features file, client, client
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
- puts "\n#{result}"
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,2 @@
1
+ require 'mkmf'
2
+ create_makefile "noyes_c"
@@ -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
+
@@ -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
+ }