int jass_call_closure(lua_State* L) { lua::jassbind* lj = (lua::jassbind*)L; if (!is_gaming()) { lj->pushnil(); return 1; } native_function::native_function* nf = (native_function::native_function*)lj->tounsigned(lua_upvalueindex(1)); size_t param = nf->get_param().size(); if ((int)param > lj->gettop()) { lj->pushnil(); return 1; } std::unique_ptr<uintptr_t[]> buffer(new uintptr_t[param]); std::vector<jass::jreal_t> real_buffer(param); std::vector<std::unique_ptr<jass::string_fake>> string_buffer(param); for (size_t i = 0; i < param; ++i) { native_function::variable_type vt = nf->get_param()[i]; switch (vt) { case native_function::TYPE_BOOLEAN: buffer[i] = lj->read_boolean(i+1); break; case native_function::TYPE_CODE: buffer[i] = (jass::jcode_t)util::singleton_nonthreadsafe<jump_func>::instance().create(lua::callback(lj, i+1), 'YDWE'); break; case native_function::TYPE_HANDLE: buffer[i] = lj->read_handle(i+1); break; case native_function::TYPE_INTEGER: buffer[i] = lj->read_integer(i+1); break; case native_function::TYPE_REAL: real_buffer[i] = lj->read_real(i+1); buffer[i] = (uintptr_t)&real_buffer[i]; break; case native_function::TYPE_STRING: string_buffer[i].reset(new jass::string_fake(lj->tostring(i+1))); buffer[i] = (jass::jstring_t)*string_buffer[i]; break; default: assert(false); buffer[i] = 0; break; } } uintptr_t retval = nf->call(buffer.get()); switch (nf->get_return()) { case native_function::TYPE_NOTHING: return 0; case native_function::TYPE_BOOLEAN: lj->push_boolean(retval); return 1; case native_function::TYPE_CODE: lj->push_code(retval); return 1; case native_function::TYPE_HANDLE: lj->push_handle(retval); return 1; case native_function::TYPE_INTEGER: lj->push_integer(retval); return 1; case native_function::TYPE_REAL: lj->push_real(retval); return 1; case native_function::TYPE_STRING: lj->push_string(retval); return 1; default: assert(false); break; } return 0; }
int main(int argc, char **argv) { // Full size, complex, buffers. Not all of which will be used for some cases. float input[kSize * kSize * 2] = {0}; float output[kSize * kSize * 2] = {0}; std::cout << std::fixed << std::setprecision(2); // Forward real to complex test. { std::cout << "Forward real to complex test." << std::endl; float signal_1d[kSize]; for (size_t i = 0; i < kSize; i++) { signal_1d[i] = 0; for (size_t k = 1; k < 5; k++) { signal_1d[i] += cos(2 * kPi * (k * (i / (float)kSize) + (k / 16.0f))); } } for (int j = 0; j < kSize; j++) { for (int i = 0; i < kSize; i++) { input[i + j * kSize] = signal_1d[i] + signal_1d[j]; } } buffer_t in = real_buffer(input); buffer_t out = complex_buffer(output, kSize / 2 + 1); int halide_result; halide_result = fft_forward_r2c(&in, &out); if (halide_result != 0) { std::cerr << "fft_forward_r2c failed returning " << halide_result << std::endl; exit(1); } for (size_t i = 1; i < 5; i++) { // Check horizontal bins float real = output[i * 2]; float imaginary = output[i * 2 + 1]; float magnitude = sqrt(real * real + imaginary * imaginary); if (fabs(magnitude - .5f) > .001) { std::cerr << "fft_forward_r2c bad magnitude for horizontal bin " << i << ":" << magnitude << std::endl; exit(1); } float phase_angle = atan2(imaginary, real); if (fabs(phase_angle - (i / 16.0f) * 2 * kPi) > .001) { std::cerr << "fft_forward_r2c bad phase angle for horizontal bin " << i << ": " << phase_angle << std::endl; exit(1); } // Check vertical bins real = output[i * 2 * kSize]; imaginary = output[i * 2 * kSize + 1]; magnitude = sqrt(real * real + imaginary * imaginary); if (fabs(magnitude - .5f) > .001) { std::cerr << "fft_forward_r2c bad magnitude for vertical bin " << i << ":" << magnitude << std::endl; exit(1); } phase_angle = atan2(imaginary, real); if (fabs(phase_angle - (i / 16.0f) * 2 * kPi) > .001) { std::cerr << "fft_forward_r2c bad phase angle for vertical bin " << i << ": " << phase_angle << std::endl; exit(1); } } // Check all other components are close to zero. for (size_t j = 0; j < kSize; j++) { for (size_t i = 0; i < kSize; i++) { // The first four non-DC bins in x and y have non-zero // values. The horizontal ones are mirrored into the // negative frequency components as well. if (!((j == 0 && ((i > 0 && i < 5) || (i > kSize - 5))) || (i == 0 && j > 0 && j < 5))) { float real = output[(j * kSize + i) * 2]; float imaginary = output[(j * kSize + i) * 2 + 1]; if (fabs(real) > .001) { std::cerr << "fft_forward_r2c real component at (" << i << ", " << j << ") is non-zero: " << real << std::endl; exit(1); } if (fabs(imaginary) > .001) { std::cerr << "fft_forward_r2c imaginary component at (" << i << ", " << j << ") is non-zero: " << imaginary << std::endl; exit(1); } } } } } // Inverse complex to real test. { std::cout << "Inverse complex to real test." << std::endl; memset(input, 0, sizeof(input)); // There are four components that get summed to form the magnitude, which we want to be 1. // The components are each of the positive and negative frequencies and each of the // real and complex components. The +/- frequencies sum algebraically and the complex // components contribute to the magnitude as the sides of triangle like any 2D vector. float term_magnitude = 1.0f / (2.0f * sqrt(2.0f)); input[2] = term_magnitude; input[3] = term_magnitude; // Negative frequencies count backward from end, no DC term input[(kSize - 1) * 2] = term_magnitude; input[(kSize - 1) * 2 + 1] = -term_magnitude; // complex conjugate buffer_t in = complex_buffer(input); buffer_t out = real_buffer(output); int halide_result; halide_result = fft_inverse_c2r(&in, &out); if (halide_result != 0) { std::cerr << "fft_inverse_c2r failed returning " << halide_result << std::endl; exit(1); } for (size_t j = 0; j < kSize; j++) { for (size_t i = 0; i < kSize; i++) { float sample = output[j * kSize + i]; float expected = cos(2 * kPi * (i / 16.0f + .125f)); if (fabs(sample - expected) > .001) { std::cerr << "fft_inverse_c2r mismatch at (" << i << ", " << j << ") " << sample << " vs. " << expected << std::endl; exit(1); } } } } // Forward complex to complex test. { std::cout << "Forward complex to complex test." << std::endl; float signal_1d_real[kSize]; float signal_1d_complex[kSize]; for (size_t i = 0; i < kSize; i++) { signal_1d_real[i] = 0; signal_1d_complex[i] = 0; for (size_t k = 1; k < 5; k++) { signal_1d_real[i] += cos(2 * kPi * (k * (i / (float)kSize) + (k / 16.0f))); signal_1d_complex[i] += sin(2 * kPi * (k * (i / (float)kSize) + (k / 16.0f))); } } for (int j = 0; j < kSize; j++) { for (int i = 0; i < kSize; i++) { input[(i + j * kSize) * 2] = signal_1d_real[i] + signal_1d_real[j]; input[(i + j * kSize) * 2 + 1] = signal_1d_complex[i] + signal_1d_complex[j]; } } buffer_t in = complex_buffer(input); buffer_t out = complex_buffer(output); int halide_result; halide_result = fft_forward_c2c(&in, &out); if (halide_result != 0) { std::cerr << "fft_forward_c2c failed returning " << halide_result << std::endl; exit(1); } for (size_t i = 1; i < 5; i++) { // Check horizontal bins float real = output[i * 2]; float imaginary = output[i * 2 + 1]; float magnitude = sqrt(real * real + imaginary * imaginary); if (fabs(magnitude - 1.0f) > .001) { std::cerr << "fft_forward_c2c bad magnitude for horizontal bin " << i << ":" << magnitude << std::endl; exit(1); } float phase_angle = atan2(imaginary, real); if (fabs(phase_angle - (i / 16.0f) * 2 * kPi) > .001) { std::cerr << "fft_forward_c2c bad phase angle for horizontal bin " << i << ": " << phase_angle << std::endl; exit(1); } // Check vertical bins real = output[i * 2 * kSize]; imaginary = output[i * 2 * kSize + 1]; magnitude = sqrt(real * real + imaginary * imaginary); if (fabs(magnitude - 1.0f) > .001) { std::cerr << "fft_forward_c2c bad magnitude for vertical bin " << i << ":" << magnitude << std::endl; exit(1); } phase_angle = atan2(imaginary, real); if (fabs(phase_angle - (i / 16.0f) * 2 * kPi) > .001) { std::cerr << "fft_forward_c2c bad phase angle for vertical bin " << i << ": " << phase_angle << std::endl; exit(1); } } // Check all other components are close to zero. for (size_t j = 0; j < kSize; j++) { for (size_t i = 0; i < kSize; i++) { // The first four non-DC bins in x and y have non-zero // values. The input is chose so the mirrored negative // frequency components are all zero due to // interference of the real and complex parts. if (!((j == 0 && (i > 0 && i < 5)) || (i == 0 && j > 0 && j < 5))) { float real = output[(j * kSize + i) * 2]; float imaginary = output[(j * kSize + i) * 2 + 1]; if (fabs(real) > .001) { std::cerr << "fft_forward_c2c real component at (" << i << ", " << j << ") is non-zero: " << real << std::endl; exit(1); } if (fabs(imaginary) > .001) { std::cerr << "fft_forward_c2c imaginary component at (" << i << ", " << j << ") is non-zero: " << imaginary << std::endl; exit(1); } } } } } // Inverse complex to complex test. { std::cout << "Inverse complex to complex test." << std::endl; memset(input, 0, sizeof(input)); input[2] = .5f; input[3] = .5f; input[(kSize - 1) * 2] = .5f; input[(kSize - 1) * 2 + 1] = .5f; // Not conjugate. Result will not be real buffer_t in = complex_buffer(input); buffer_t out = complex_buffer(output); int halide_result; halide_result = fft_inverse_c2c(&in, &out); if (halide_result != 0) { std::cerr << "fft_inverse_c2c failed returning " << halide_result << std::endl; exit(1); } for (size_t j = 0; j < kSize; j++) { for (size_t i = 0; i < kSize; i++) { float real_sample = output[(j * kSize + i) * 2]; float imaginary_sample = output[(j * kSize + i) * 2 + 1]; float real_expected = 1 / sqrt(2) * (cos(2 * kPi * (i / 16.0f + .125)) + cos(2 * kPi * (i * (kSize - 1) / 16.0f + .125))); float imaginary_expected = 1 / sqrt(2) * (sin(2 * kPi * (i / 16.0f + .125)) + sin(2 * kPi * (i * (kSize - 1) / 16.0f + .125))); if (fabs(real_sample - real_expected) > .001) { std::cerr << "fft_inverse_c2c real mismatch at (" << i << ", " << j << ") " << real_sample << " vs. " << real_expected << std::endl; exit(1); } if (fabs(imaginary_sample - imaginary_expected) > .001) { std::cerr << "fft_inverse_c2c imaginary mismatch at (" << i << ", " << j << ") " << imaginary_sample << " vs. " << imaginary_expected << std::endl; exit(1); } } } } exit(0); }