hornetseye-fftw3 0.1.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.md ADDED
@@ -0,0 +1,28 @@
1
+ hornetseye-fftw3
2
+ ================
3
+
4
+ **Author**: Jan Wedekind
5
+ **Copyright**: 2011
6
+ **License**: GPL
7
+
8
+ Synopsis
9
+ --------
10
+
11
+ This Ruby extension provides bindings for the FFTW3 library.
12
+
13
+ Installation
14
+ ------------
15
+
16
+ *hornetseye-fftw3* requires the FFTW3 libraries. If you are running Debian or (K)ubuntu, you can install them like this:
17
+
18
+ $ sudo aptitude install libfftw3-dev
19
+
20
+ To install this Ruby extension, use the following command:
21
+
22
+ $ sudo gem install hornetseye-fftw3
23
+
24
+ Alternatively you can build and install the Ruby extension from source as follows:
25
+
26
+ $ rake
27
+ $ sudo rake install
28
+
data/Rakefile ADDED
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env ruby
2
+ require 'date'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/loaders/makefile'
7
+ require 'rbconfig'
8
+ require 'tempfile'
9
+
10
+ PKG_NAME = 'hornetseye-fftw3'
11
+ PKG_VERSION = '0.1.0'
12
+ CFG = RbConfig::CONFIG
13
+ CXX = ENV[ 'CXX' ] || 'g++'
14
+ RB_FILES = FileList[ 'lib/**/*.rb' ]
15
+ CC_FILES = FileList[ 'ext/*.cc' ]
16
+ HH_FILES = FileList[ 'ext/*.hh' ] + FileList[ 'ext/*.tcc' ]
17
+ TC_FILES = FileList[ 'test/tc_*.rb' ]
18
+ TS_FILES = FileList[ 'test/ts_*.rb' ]
19
+ SO_FILE = "ext/#{PKG_NAME.tr '\-', '_'}.#{CFG[ 'DLEXT' ]}"
20
+ PKG_FILES = [ 'Rakefile', 'README.md', 'COPYING', '.document' ] +
21
+ RB_FILES + CC_FILES + HH_FILES + TS_FILES + TC_FILES
22
+ BIN_FILES = [ 'README.md', 'COPYING', '.document', SO_FILE ] +
23
+ RB_FILES + TS_FILES + TC_FILES
24
+ SUMMARY = %q{Fourier transforms}
25
+ DESCRIPTION = %q{This Ruby extension provides bindings for the FFTW3 library.}
26
+ AUTHOR = %q{Jan Wedekind}
27
+ EMAIL = %q{jan@wedesoft.de}
28
+ HOMEPAGE = %q{http://wedesoft.github.com/hornetseye-fftw3/}
29
+
30
+ OBJ = CC_FILES.ext 'o'
31
+ $CXXFLAGS = "-DNDEBUG -DHAVE_CONFIG_H -D__STDC_CONSTANT_MACROS #{CFG[ 'CPPFLAGS' ]} #{CFG[ 'CFLAGS' ]}"
32
+ if CFG[ 'rubyhdrdir' ]
33
+ $CXXFLAGS = "#{$CXXFLAGS} -I#{CFG[ 'rubyhdrdir' ]} " +
34
+ "-I#{CFG[ 'rubyhdrdir' ]}/#{CFG[ 'arch' ]}"
35
+ else
36
+ $CXXFLAGS = "#{$CXXFLAGS} -I#{CFG[ 'archdir' ]}"
37
+ end
38
+ $LIBRUBYARG = "-L#{CFG[ 'libdir' ]} #{CFG[ 'LIBRUBYARG' ]} #{CFG[ 'LDFLAGS' ]} " +
39
+ "#{CFG[ 'SOLIBS' ]} #{CFG[ 'DLDLIBS' ]}"
40
+ $SITELIBDIR = CFG[ 'sitelibdir' ]
41
+ $SITEARCHDIR = CFG[ 'sitearchdir' ]
42
+ $LDSHARED = CFG[ 'LDSHARED' ][ CFG[ 'LDSHARED' ].index( ' ' ) .. -1 ]
43
+
44
+ task :default => :all
45
+
46
+ desc 'Compile Ruby extension (default)'
47
+ task :all => [ SO_FILE ]
48
+
49
+ file SO_FILE => OBJ do |t|
50
+ sh "#{CXX} -shared -o #{t.name} #{OBJ} -lfftw3 -lfftw3f #{$LIBRUBYARG}"
51
+ end
52
+
53
+ task :test => [ SO_FILE ]
54
+
55
+ desc 'Install Ruby extension'
56
+ task :install => :all do
57
+ verbose true do
58
+ for f in RB_FILES do
59
+ FileUtils.mkdir_p "#{$SITELIBDIR}/#{File.dirname f.gsub( /^lib\//, '' )}"
60
+ FileUtils.cp_r f, "#{$SITELIBDIR}/#{f.gsub( /^lib\//, '' )}"
61
+ end
62
+ FileUtils.mkdir_p $SITEARCHDIR
63
+ FileUtils.cp SO_FILE, "#{$SITEARCHDIR}/#{File.basename SO_FILE}"
64
+ end
65
+ end
66
+
67
+ desc 'Uninstall Ruby extension'
68
+ task :uninstall do
69
+ verbose true do
70
+ for f in RB_FILES do
71
+ FileUtils.rm_f "#{$SITELIBDIR}/#{f.gsub /^lib\//, ''}"
72
+ end
73
+ FileUtils.rm_f "#{$SITEARCHDIR}/#{File.basename SO_FILE}"
74
+ end
75
+ end
76
+
77
+ Rake::TestTask.new do |t|
78
+ t.libs << 'ext'
79
+ t.test_files = TC_FILES
80
+ end
81
+
82
+ begin
83
+ require 'yard'
84
+ YARD::Rake::YardocTask.new :yard do |y|
85
+ y.files << RB_FILES
86
+ end
87
+ rescue LoadError
88
+ STDERR.puts 'Please install \'yard\' if you want to generate documentation'
89
+ end
90
+
91
+ Rake::PackageTask.new PKG_NAME, PKG_VERSION do |p|
92
+ p.need_tar = true
93
+ p.package_files = PKG_FILES
94
+ end
95
+
96
+ begin
97
+ require 'rubygems'
98
+ require 'rubygems/builder'
99
+ $SPEC = Gem::Specification.new do |s|
100
+ s.name = PKG_NAME
101
+ s.version = PKG_VERSION
102
+ s.platform = Gem::Platform::RUBY
103
+ s.date = Date.today.to_s
104
+ s.summary = SUMMARY
105
+ s.description = DESCRIPTION
106
+ s.author = AUTHOR
107
+ s.email = EMAIL
108
+ s.homepage = HOMEPAGE
109
+ s.files = PKG_FILES
110
+ s.test_files = TC_FILES
111
+ s.require_paths = [ 'lib', 'ext' ]
112
+ s.rubyforge_project = %q{hornetseye}
113
+ s.extensions = %w{Rakefile}
114
+ s.has_rdoc = 'yard'
115
+ s.extra_rdoc_files = []
116
+ s.rdoc_options = %w{--no-private}
117
+ s.add_dependency %<malloc>, [ '~> 1.1' ]
118
+ s.add_dependency %<multiarray>, [ '~> 0.20' ]
119
+ s.add_development_dependency %q{rake}
120
+ end
121
+ GEM_SOURCE = "#{PKG_NAME}-#{PKG_VERSION}.gem"
122
+ $BINSPEC = Gem::Specification.new do |s|
123
+ s.name = PKG_NAME
124
+ s.version = PKG_VERSION
125
+ s.platform = Gem::Platform::CURRENT
126
+ s.date = Date.today.to_s
127
+ s.summary = SUMMARY
128
+ s.description = DESCRIPTION
129
+ s.author = AUTHOR
130
+ s.email = EMAIL
131
+ s.homepage = HOMEPAGE
132
+ s.files = BIN_FILES
133
+ s.test_files = TC_FILES
134
+ s.require_paths = [ 'lib', 'ext' ]
135
+ s.rubyforge_project = %q{hornetseye}
136
+ s.has_rdoc = 'yard'
137
+ s.extra_rdoc_files = []
138
+ s.rdoc_options = %w{--no-private}
139
+ s.add_dependency %<malloc>, [ '~> 1.1' ]
140
+ s.add_dependency %<multiarray>, [ '~> 0.20' ]
141
+ end
142
+ GEM_BINARY = "#{PKG_NAME}-#{PKG_VERSION}-#{$BINSPEC.platform}.gem"
143
+ desc "Build the gem file #{GEM_SOURCE}"
144
+ task :gem => [ "pkg/#{GEM_SOURCE}" ]
145
+ file "pkg/#{GEM_SOURCE}" => [ 'pkg' ] + $SPEC.files do
146
+ when_writing 'Creating GEM' do
147
+ Gem::Builder.new( $SPEC ).build
148
+ verbose true do
149
+ FileUtils.mv GEM_SOURCE, "pkg/#{GEM_SOURCE}"
150
+ end
151
+ end
152
+ end
153
+ desc "Build the gem file #{GEM_BINARY}"
154
+ task :gem_binary => [ "pkg/#{GEM_BINARY}" ]
155
+ file "pkg/#{GEM_BINARY}" => [ 'pkg' ] + $BINSPEC.files do
156
+ when_writing 'Creating binary GEM' do
157
+ Gem::Builder.new( $BINSPEC ).build
158
+ verbose true do
159
+ FileUtils.mv GEM_BINARY, "pkg/#{GEM_BINARY}"
160
+ end
161
+ end
162
+ end
163
+ rescue LoadError
164
+ STDERR.puts 'Please install \'rubygems\' if you want to create Gem packages'
165
+ end
166
+
167
+ rule '.o' => '.cc' do |t|
168
+ sh "#{CXX} #{$CXXFLAGS} -c -o #{t.name} #{t.source}"
169
+ end
170
+
171
+ file ".depends.mf" do |t|
172
+ sh "g++ -MM #{CC_FILES.join ' '} | " +
173
+ "sed -e :a -e N -e 's/\\n/\\$/g' -e ta | " +
174
+ "sed -e 's/ *\\\\\\$ */ /g' -e 's/\\$/\\n/g' | sed -e 's/^/ext\\//' > #{t.name}"
175
+ end
176
+ CC_FILES.each do |t|
177
+ file t.ext(".o") => t
178
+ end
179
+ import ".depends.mf"
180
+
181
+ CLEAN.include 'ext/*.o'
182
+ CLOBBER.include SO_FILE, 'doc', '.yardoc', '.depends.mf'
183
+
data/ext/error.hh ADDED
@@ -0,0 +1,50 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
+ #ifndef ERROR_HH
17
+ #define ERROR_HH
18
+
19
+ #include <exception>
20
+ #include <sstream>
21
+
22
+ class Error: public std::exception
23
+ {
24
+ public:
25
+ Error(void) {}
26
+ Error( Error &e ): std::exception( e )
27
+ { m_message << e.m_message.str(); }
28
+ virtual ~Error(void) throw() {}
29
+ template< typename T >
30
+ std::ostream &operator<<( const T &t )
31
+ { m_message << t; return m_message; }
32
+ std::ostream &operator<<( std::ostream& (*__pf)(std::ostream&) )
33
+ { (*__pf)( m_message ); return m_message; }
34
+ virtual const char* what(void) const throw() {
35
+ temp = m_message.str();
36
+ return temp.c_str();
37
+ }
38
+ protected:
39
+ std::ostringstream m_message;
40
+ mutable std::string temp;
41
+ };
42
+
43
+ #define ERRORMACRO( condition, class, params, message ) \
44
+ if ( !( condition ) ) { \
45
+ class _e params; \
46
+ _e << message; \
47
+ throw _e; \
48
+ };
49
+
50
+ #endif
data/ext/init.cc ADDED
@@ -0,0 +1,38 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Jan Wedekind
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
+ #include "rubyinc.hh"
17
+ #include "node.hh"
18
+
19
+ #ifdef WIN32
20
+ #define DLLEXPORT __declspec(dllexport)
21
+ #define DLLLOCAL
22
+ #else
23
+ #define DLLEXPORT __attribute__ ((visibility("default")))
24
+ #define DLLLOCAL __attribute__ ((visibility("hidden")))
25
+ #endif
26
+
27
+ extern "C" DLLEXPORT void Init_hornetseye_fftw3(void);
28
+
29
+ extern "C" {
30
+
31
+ void Init_hornetseye_fftw3(void)
32
+ {
33
+ VALUE rbHornetseye = rb_define_module( "Hornetseye" );
34
+ Node::registerRubyClass( rbHornetseye );
35
+ rb_require( "hornetseye_fftw3_ext.rb" );
36
+ }
37
+
38
+ }
data/ext/node.cc ADDED
@@ -0,0 +1,223 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Jan Wedekind
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
+ #include <iostream>
17
+
18
+ #include <boost/shared_array.hpp>
19
+ #include <fftw3.h>
20
+ #include "error.hh"
21
+ #include "node.hh"
22
+
23
+ using namespace boost;
24
+ using namespace std;
25
+
26
+ VALUE Node::cRubyClass = Qnil;
27
+
28
+ VALUE Node::mModule = Qnil;
29
+
30
+ VALUE Node::registerRubyClass( VALUE module )
31
+ {
32
+ mModule = module;
33
+ cRubyClass = rb_define_class_under( module, "Node", rb_cObject );
34
+ rb_define_method( cRubyClass, "fft", RUBY_METHOD_FUNC( wrapFFT ), 1 );
35
+ rb_define_method( cRubyClass, "rfft", RUBY_METHOD_FUNC( wrapRFFT ), 1 );
36
+ return cRubyClass;
37
+ }
38
+
39
+ VALUE Node::wrapFFT( VALUE rbSelf, VALUE rbForward )
40
+ {
41
+ VALUE rbRetVal = Qnil;
42
+ try {
43
+ int sign = rbForward == Qtrue ? FFTW_FORWARD : FFTW_BACKWARD;
44
+ VALUE rbMalloc = rb_funcall( rbSelf, rb_intern( "memory" ), 0 );
45
+ VALUE rbTypecode = rb_funcall( rbSelf, rb_intern( "typecode" ), 0 );
46
+ VALUE rbSize = rb_funcall( rbSelf, rb_intern( "size" ), 0 );
47
+ int size = NUM2INT( rbSize );
48
+ VALUE rbShape = rb_funcall( rbSelf, rb_intern( "shape" ), 0 );
49
+ int rank = RARRAY_LEN( rbShape );
50
+ shared_array< int > n( new int[ rank ] );
51
+ for ( int i=0; i<rank; i++ )
52
+ n[ rank - 1 - i ] = NUM2INT( RARRAY_PTR( rbShape )[i] );
53
+ VALUE rbDest = Qnil;
54
+ if ( rb_funcall( rbTypecode, rb_intern( "==" ), 1,
55
+ rb_const_get( mModule, rb_intern( "SCOMPLEX" ) ) ) == Qtrue ) {
56
+ assert( sizeof( fftwf_complex ) == sizeof( float ) * 2 );
57
+ fftwf_complex *source;
58
+ Data_Get_Struct( rbMalloc, fftwf_complex, source );
59
+ fftwf_complex *dest = ALLOC_N( fftwf_complex, size );
60
+ rbDest = Data_Wrap_Struct( rb_const_get( mModule, rb_intern( "Malloc" ) ), 0, xfree,
61
+ (void *)dest );
62
+ rb_ivar_set( rbDest, rb_intern( "@size" ), INT2NUM( size * sizeof( fftwf_complex ) ) );
63
+ fftwf_plan plan =
64
+ fftwf_plan_dft( rank, n.get(), source, dest, sign,
65
+ FFTW_ESTIMATE | FFTW_PRESERVE_INPUT );
66
+ ERRORMACRO( plan != NULL, Error, , "Error creating FFTW plan" );
67
+ fftwf_execute( plan );
68
+ fftwf_destroy_plan( plan );
69
+ } else if ( rb_funcall( rbTypecode, rb_intern( "==" ), 1,
70
+ rb_const_get( mModule, rb_intern( "DCOMPLEX" ) ) ) == Qtrue ) {
71
+ assert( sizeof( fftw_complex ) == sizeof( double ) * 2 );
72
+ fftw_complex *source;
73
+ Data_Get_Struct( rbMalloc, fftw_complex, source );
74
+ fftw_complex *dest = ALLOC_N( fftw_complex, size );
75
+ rbDest = Data_Wrap_Struct( rb_const_get( mModule, rb_intern( "Malloc" ) ), 0, xfree,
76
+ (void *)dest );
77
+ rb_ivar_set( rbDest, rb_intern( "@size" ), INT2NUM( size * sizeof( fftw_complex ) ) );
78
+ fftw_plan plan =
79
+ fftw_plan_dft( rank, n.get(), source, dest, sign,
80
+ FFTW_ESTIMATE | FFTW_PRESERVE_INPUT );
81
+ ERRORMACRO( plan != NULL, Error, , "Error creating FFTW plan" );
82
+ fftw_execute( plan );
83
+ fftw_destroy_plan( plan );
84
+ } else {
85
+ ERRORMACRO( false, Error, ,
86
+ "This datatype is not supported for the selected transform" );
87
+ };
88
+ rbRetVal = rb_funcall2( rb_funcall( rb_const_get( mModule, rb_intern( "Sequence" ) ),
89
+ rb_intern( "import" ), 3,
90
+ rbTypecode, rbDest, rbSize ),
91
+ rb_intern( "reshape" ), rank, RARRAY_PTR(rbShape) );
92
+ } catch ( std::exception &e ) {
93
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
94
+ };
95
+ return rbRetVal;
96
+ }
97
+
98
+ VALUE Node::wrapRFFT( VALUE rbSelf, VALUE rbForward )
99
+ {
100
+ VALUE rbRetVal = Qnil;
101
+ try {
102
+ int sign = rbForward == Qtrue ? FFTW_FORWARD : FFTW_BACKWARD;
103
+ VALUE rbMalloc = rb_funcall( rbSelf, rb_intern( "memory" ), 0 );
104
+ VALUE rbTypecode = rb_funcall( rbSelf, rb_intern( "typecode" ), 0 );
105
+ VALUE rbInSize = rb_funcall( rbSelf, rb_intern( "size" ), 0 );
106
+ int inSize = NUM2INT( rbInSize );
107
+ VALUE rbShape = rb_funcall( rbSelf, rb_intern( "shape" ), 0 );
108
+ int rank = RARRAY_LEN( rbShape );
109
+ shared_array< int > n( new int[ rank ] );
110
+ for ( int i=0; i<rank; i++ )
111
+ n[ rank - 1 - i ] = NUM2INT( RARRAY_PTR( rbShape )[i] );
112
+ VALUE rbDest = Qnil;
113
+ VALUE rbRetType = Qnil;
114
+ int size = 0;
115
+ if ( rank > 0 ) {
116
+ if ( sign == FFTW_FORWARD ) {
117
+ ERRORMACRO( n[ rank - 1 ] % 2 == 0, Error, ,
118
+ "First dimension of array must be even for discrete "
119
+ "fourier transform of real data" );
120
+ int half = n[ rank - 1 ] / 2 + 1;
121
+ size = inSize / n[ rank - 1 ] * half;
122
+ RARRAY_PTR(rbShape)[0] = INT2NUM(half);
123
+ } else {
124
+ int twice = ( n[ rank - 1 ] - 1 ) * 2;
125
+ size = inSize / n[ rank - 1 ] * twice;
126
+ RARRAY_PTR(rbShape)[0] = INT2NUM(twice);
127
+ n[ rank - 1 ] = twice;
128
+ };
129
+ };
130
+ if ( ( rb_funcall( rbTypecode, rb_intern( "==" ), 1,
131
+ rb_const_get( mModule,
132
+ rb_intern( "SFLOAT" ) ) ) ==
133
+ Qtrue &&
134
+ sign == FFTW_FORWARD ) ||
135
+ ( rb_funcall( rbTypecode, rb_intern( "==" ), 1,
136
+ rb_const_get( mModule,
137
+ rb_intern( "SCOMPLEX" ) ) ) ==
138
+ Qtrue &&
139
+ sign == FFTW_BACKWARD ) ) {
140
+ assert( sizeof( fftwf_complex ) == sizeof( float ) * 2 );
141
+ fftwf_complex *source;
142
+ Data_Get_Struct( rbMalloc, fftwf_complex, source );
143
+ void *dest;
144
+ fftwf_plan plan;
145
+ shared_array< fftwf_complex > copy;
146
+ int retTypeSize;
147
+ if ( sign == FFTW_FORWARD ) {
148
+ dest = ALLOC_N( fftwf_complex, size );
149
+ retTypeSize = sizeof( fftwf_complex );
150
+ plan = fftwf_plan_dft_r2c( rank, n.get(), (float *)source,
151
+ (fftwf_complex *)dest,
152
+ FFTW_ESTIMATE | FFTW_PRESERVE_INPUT );
153
+ rbRetType = rb_const_get( mModule, rb_intern( "SCOMPLEX" ) );
154
+ } else {
155
+ dest = ALLOC_N( float, size );
156
+ retTypeSize = sizeof( float );
157
+ // FFTW_PRESERVE_INPUT not supported in this case.
158
+ copy = shared_array< fftwf_complex >( new fftwf_complex[ inSize ] );
159
+ memcpy( copy.get(), source, inSize * sizeof( fftwf_complex ) );
160
+ plan = fftwf_plan_dft_c2r( rank, n.get(), (fftwf_complex *)copy.get(),
161
+ (float *)dest, FFTW_ESTIMATE );
162
+ rbRetType = rb_const_get( mModule, rb_intern( "SFLOAT" ) );
163
+ };
164
+ rbDest = Data_Wrap_Struct( rb_const_get( mModule, rb_intern( "Malloc" ) ), 0, xfree,
165
+ (void *)dest );
166
+ rb_ivar_set( rbDest, rb_intern( "@size" ), INT2NUM( size * retTypeSize ) );
167
+ ERRORMACRO( plan != NULL, Error, , "Error creating FFTW plan" );
168
+ fftwf_execute( plan );
169
+ fftwf_destroy_plan( plan );
170
+ } else if ( ( rb_funcall( rbTypecode, rb_intern( "==" ), 1,
171
+ rb_const_get( mModule,
172
+ rb_intern( "DFLOAT" ) ) ) ==
173
+ Qtrue &&
174
+ sign == FFTW_FORWARD ) ||
175
+ ( rb_funcall( rbTypecode, rb_intern( "==" ), 1,
176
+ rb_const_get( mModule,
177
+ rb_intern( "DCOMPLEX" ) ) ) ==
178
+ Qtrue &&
179
+ sign == FFTW_BACKWARD ) ) {
180
+ assert( sizeof( fftw_complex ) == sizeof( double ) * 2 );
181
+ fftw_complex *source;
182
+ Data_Get_Struct( rbMalloc, fftw_complex, source );
183
+ void *dest;
184
+ fftw_plan plan;
185
+ shared_array< fftw_complex > copy;
186
+ int retTypeSize;
187
+ if ( sign == FFTW_FORWARD ) {
188
+ dest = ALLOC_N( fftw_complex, size );
189
+ retTypeSize = sizeof( fftw_complex );
190
+ plan = fftw_plan_dft_r2c( rank, n.get(), (double *)source,
191
+ (fftw_complex *)dest,
192
+ FFTW_ESTIMATE | FFTW_PRESERVE_INPUT );
193
+ rbRetType = rb_const_get( mModule, rb_intern( "DCOMPLEX" ) );
194
+ } else {
195
+ dest = ALLOC_N( double, size );
196
+ retTypeSize = sizeof( double );
197
+ // FFTW_PRESERVE_INPUT not supported in this case.
198
+ copy = shared_array< fftw_complex >( new fftw_complex[ inSize ] );
199
+ memcpy( copy.get(), source, inSize * sizeof( fftw_complex ) );
200
+ plan = fftw_plan_dft_c2r( rank, n.get(), (fftw_complex *)copy.get(),
201
+ (double *)dest, FFTW_ESTIMATE );
202
+ rbRetType = rb_const_get( mModule, rb_intern( "DFLOAT" ) );
203
+ };
204
+ rbDest = Data_Wrap_Struct( rb_const_get( mModule, rb_intern( "Malloc" ) ), 0, xfree,
205
+ (void *)dest );
206
+ rb_ivar_set( rbDest, rb_intern( "@size" ), INT2NUM( size * retTypeSize ) );
207
+ ERRORMACRO( plan != NULL, Error, , "Error creating FFTW plan" );
208
+ fftw_execute( plan );
209
+ fftw_destroy_plan( plan );
210
+ } else {
211
+ ERRORMACRO( false, Error, ,
212
+ "This datatype is not supported for the selected transform" );
213
+ };
214
+ rbRetVal = rb_funcall2( rb_funcall( rb_const_get( mModule, rb_intern( "Sequence" ) ),
215
+ rb_intern( "import" ), 3,
216
+ rbRetType, rbDest, INT2NUM( size ) ),
217
+ rb_intern( "reshape" ), rank, RARRAY_PTR(rbShape) );
218
+ } catch ( std::exception &e ) {
219
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
220
+ };
221
+ return rbRetVal;
222
+ }
223
+