// file: $isip_ifc/class/algo/Window/win_05.cc // version: $Id: win_05.cc 10482 2006-03-14 21:51:09Z srinivas $ // // isip include files // #include "Window.h" // method: apply // // arguments: // Vector& output: (output) output data // const Vector< CircularBuffer >& input: (input) input data // // return: a bool8 value indicating status // // this method calls the appropriate computation methods // bool8 Window::apply(Vector& output_a, const Vector< CircularBuffer >& input_a) { // determine the number of input channels and force the output to be // that number // int32 len = input_a.length(); output_a.setLength(len); bool8 res = true; // start the debugging output // displayStart(this); // loop over the channels and call the compute method // for (int32 c = 0; c < len; c++) { // display the channel number // displayChannel(c); // call AlgorithmData::makeVectorFloat to force the output vector for // this channel to be a VectorFloat, use the CircularBuffer // directly on the input for this channel // res &= compute(output_a(c).makeVectorFloat(), input_a(c), input_a(c)(0).getCoefType(), c); // set the coefficient type for the output // output_a(c).setCoefType(input_a(c)(0).getCoefType()); } // finish the debugging output // displayFinish(this); // exit gracefully // return res; } // method: compute // // arguments: // VectorFloat& vector_out: (output) operand // const VectorFloat& vector_in: (input) operand // AlgorithmData::COEF_TYPE coef_type: (input) coeff type of input signal // int32 channel_index: (input) the channel index of input signal // // return: a bool8 value containing status // // this method applies the specified window on the input vector // bool8 Window::compute(VectorFloat& vector_out_a, const VectorFloat& vector_in_a, AlgorithmData::COEF_TYPE coef_type_a, int32 channel_index_a) { // declare local variables // bool8 status = false; // check whether we need to initialize // if (!is_valid_d) { init(); } // algorithm: *all* standard algorithms // if ((algorithm_d == RECTANGULAR) || (algorithm_d == BARTLETT) || (algorithm_d == BLACKMAN) || (algorithm_d == DOLPH_CHEBYSHEV) || (algorithm_d == GAUSSIAN) || (algorithm_d == HAMMING) || (algorithm_d == HANNING) || (algorithm_d == KAISER) || (algorithm_d == LIFTER) || (algorithm_d == CUSTOM)) { status = computeCommon(vector_out_a, vector_in_a); } // error: unknown algorithm // else { status = Error::handle(name(), L"compute", ERR_UNKALG, __FILE__, __LINE__); } // possibly display the data // display(vector_out_a, vector_in_a, name()); // exit gracefully // return status; } // method: compute // // arguments: // VectorComplexFloat& vector_out: (output) operand // const VectorComplexFloat& vector_in: (input) operand // AlgorithmData::COEF_TYPE coef_type: (input) coeff type of input signal // int32 channel_index: (input) the channel index of input signal // // return: a bool8 value containing status // // this method applies the specified window on the input vector // bool8 Window::compute(VectorComplexFloat& vector_out_a, const VectorComplexFloat& vector_in_a, AlgorithmData::COEF_TYPE coef_type_a, int32 channel_index_a) { // declare local variables // bool8 status = false; // check whether we need to initialize // if (!is_valid_d) { init(); } // algorithm: *all* standard algorithms // if ((algorithm_d == RECTANGULAR) || (algorithm_d == BARTLETT) || (algorithm_d == BLACKMAN) || (algorithm_d == DOLPH_CHEBYSHEV) || (algorithm_d == GAUSSIAN) || (algorithm_d == HAMMING) || (algorithm_d == HANNING) || (algorithm_d == KAISER) || (algorithm_d == LIFTER) || (algorithm_d == CUSTOM)) { status = computeCommon(vector_out_a, vector_in_a); } // error: unknown algorithm // else { status = Error::handle(name(), L"compute", ERR_UNKALG, __FILE__, __LINE__); } // possibly display the data // display(vector_out_a, vector_in_a, name()); // exit gracefully // return status; } // method: compute // // arguments: // VectorFloat& output: (output) output data // const CircularBuffer& input: (input) input data // AlgorithmData::COEF_TYPE coef_type: (input) coeff type of input signal // int32 channel_index: (input) the channel index of input signal // // return: a bool8 value containing status // // this method applies the specified window on the input channel // bool8 Window::compute(VectorFloat& output_a, const CircularBuffer& input_a, AlgorithmData::COEF_TYPE coef_type_a, int32 channel_index_a) { // for FRAME_INTERNAL mode, we just process what data we have // if (cmode_d == FRAME_INTERNAL) { return compute(output_a, input_a(0).getVectorFloat(), coef_type_a, channel_index_a); } float32 win_nsamp = duration_d * sample_freq_d; // compute the number of sampled in the frame from the input vector // size. Note that this may lead to a different number of samples in // the frame than the one computed by multiplying the sampling // frequency and the frame duration. // float32 frame_nsamp = (float32)input_a(0).getVectorFloat().length(); if (win_nsamp < frame_nsamp) { VectorFloat buf; if (alignment_d == LEFT) { // because window size is smaller than frame size, just moving // the specified number of elements via the move method // buf.move(input_a(0).getVectorFloat(), (int32)Integral::round(win_nsamp), 0, 0); // apply the window function // return compute(output_a, buf, coef_type_a, channel_index_a); } else if (alignment_d == RIGHT) { // because window size is smaller than frame size, just moving // the specified number of elements via the move method // buf.move(input_a(0).getVectorFloat(), (int32)Integral::round(win_nsamp), (int32)Integral::round(frame_nsamp - win_nsamp), 0); // apply the window function // return compute(output_a, buf, coef_type_a, channel_index_a); } else if (alignment_d == CENTER) { // moving equally forward and backward // // we will copy the middle (current) frame no matter what, so // subtract it out from the totals. we will use floor for the // left calculation which will bias us by at most half a sample // into the past leaving the total number of samples unchanged. // int32 left_nsamp = (int32)Integral::floor(frame_nsamp / 2.0 - win_nsamp / 2.0 + 0.0001); buf.move(input_a(0).getVectorFloat(), (int32)Integral::round(win_nsamp), left_nsamp, 0); // apply the window function // return compute(output_a, buf, coef_type_a, channel_index_a); } // error // return Error::handle(name(), L"compute", Error::NOT_IMPLEM, __FILE__, __LINE__); } // make sure there is enough data // if ((input_a.getNumForward() < getLeadingPad()) || (input_a.getNumBackward() < getTrailingPad())) { return Error::handle(name(), L"compute", ERR, __FILE__, __LINE__); } // if window size is almost equal to frame size using FRAME_INTERNAL // mode // if (Integral::almostEqual(win_nsamp, frame_nsamp)) { return compute(output_a, input_a(0).getVectorFloat(), coef_type_a, channel_index_a); } VectorFloat buf; if (alignment_d == LEFT) { int32 frame = 0; float32 num_left = win_nsamp; while (num_left > 0) { // while there are still full frames to copy, use concat // if (num_left > frame_nsamp) { buf.concat(input_a(frame).getVectorFloat()); num_left -= frame_nsamp; } // for the last frame only copy over the specified number of // elements via the move method // else { // check if we have at least one sample left to move // int32 n_l = (int32)Integral::round(num_left); if (n_l == 0) { break; } buf.move(input_a(frame).getVectorFloat(), n_l, 0, buf.length()); num_left = 0; } frame++; } // apply the window function // return compute(output_a, buf, coef_type_a, channel_index_a); } else if (alignment_d == RIGHT) { Float num_frames = win_nsamp / frame_nsamp; int32 frame = (int32)Integral::ceil(num_frames); int32 index = frame - 1; // this is the number of samples not included from the first frame // int32 first_offset = (int32)Integral::round(frame * frame_nsamp - win_nsamp); int32 first_nelem = (int32)Integral::round(frame_nsamp - first_offset); float32 num_left = win_nsamp; bool8 initialization = true; while ((int32)num_left > 0) { // for the first frame we probably don't copy all samples, just // a right-aligned pre-specified number of samples. // if (initialization) { buf.move(input_a(-index).getVectorFloat(), first_nelem, first_offset, 0); num_left -= first_nelem; initialization = false; } // for all other frames we copy the entire frame // else { buf.concat(input_a(-index).getVectorFloat()); num_left -= frame_nsamp; } index--; } // apply the window function // return compute(output_a, buf, coef_type_a, channel_index_a); } else if (alignment_d == CENTER) { int32 num_frames = (int32)Integral::ceil(win_nsamp / frame_nsamp); // case 0: a window is less than or equal to the frame size, only // copy from one the middle of the current frame // if (num_frames == 1) { int32 start_offset = (int32)Integral::floor((frame_nsamp / 2.0) - (win_nsamp / 2.0)); buf.move(input_a(0).getVectorFloat(), (int32)Integral::ceil(win_nsamp), start_offset, 0); } // else we must span frames -- moving equally forward and backward // else { // we will copy the middle (current) frame no matter what, so // subtract it out from the totals. we will use floor for the // left calculation which will bias us by at most half a sample // into the past leaving the total number of samples unchanged. // int32 left_nsamp = (int32)Integral::floor(win_nsamp / 2.0 - frame_nsamp / 2.0); int32 right_nsamp = (int32)Integral::ceil(win_nsamp / 2.0 - frame_nsamp / 2.0); int32 first_frame = (int32)Integral::ceil(left_nsamp / frame_nsamp); int32 first_offset = first_frame * (int32)Integral::round(frame_nsamp) - left_nsamp; int32 first_nelem = (int32)Integral::round(frame_nsamp) - first_offset; for (int32 index = first_frame; left_nsamp > 0; ) { if (index == first_frame) { buf.move(input_a(-index).getVectorFloat(), first_nelem, first_offset, 0); left_nsamp -= first_nelem; } else { buf.concat(input_a(-index).getVectorFloat()); left_nsamp -= (int32)Integral::round(frame_nsamp); } } // copy the middle frame // buf.concat(input_a(0).getVectorFloat()); int32 index = 1; // now copy the future frames // while (right_nsamp > 0) { // while there are still full frames to copy, use concat // if (right_nsamp > frame_nsamp) { buf.concat(input_a(index).getVectorFloat()); right_nsamp -= (int32)Integral::round(frame_nsamp); } // for the last frame only copy over the specified number of // elements via the move method // else { buf.move(input_a(index).getVectorFloat(), (int32)Integral::ceil(right_nsamp), 0, buf.length()); right_nsamp = 0; } index++; } } // apply the window function // return compute(output_a, buf, coef_type_a, channel_index_a); } // error // return Error::handle(name(), L"compute", Error::NOT_IMPLEM, __FILE__, __LINE__); } // method: computeCommon // // arguments: // VectorFloat& vector_out: (output) operand // const VectorFloat& vector_in: (input) operand // // return: a bool8 value containing status // // this method applies the window on the input vector and is called by the // public compute method // bool8 Window::computeCommon(VectorFloat& vector_out_a, const VectorFloat& vector_in_a) { // set the size of the window // int32 len = vector_in_a.length(); setSize(len); vector_out_a.setLength(len); // if window is not set then initialize the window // if (!is_valid_d) { init(); } // now apply // for (int32 i = 0; i < len; i++) { vector_out_a(i) = data_d(i) * vector_in_a(i); } // exit gracefully // return true; } // method: computeCommon // // arguments: // VectorComplexFloat& vector_out: (output) operand // const VectorComplexFloat& vector_in: (input) operand // // return: a bool8 value containing status // // this method applies the window on the input vector and is called by the // public compute method // bool8 Window::computeCommon(VectorComplexFloat& vector_out_a, const VectorComplexFloat& vector_in_a) { // set the size of the window // int32 len = vector_in_a.length(); setSize(len); vector_out_a.setLength(len); // if window is not set then initialize the window // if (!is_valid_d) { init(); } // now apply // for (int32 i = 0; i < len; i++) { vector_out_a(i) = complexfloat((float32)data_d(i) * (float32)vector_in_a(i).real(), (float32)data_d(i) * (float32)vector_in_a(i).imag()); } // exit gracefully // return true; }