/**
* > Cyclic rotation for phase-zero windowing
*
* [![npm install dsp-fftshift](https://nodei.co/npm/dsp-fftshift.png?mini=true)](https://npmjs.org/package/dsp-fftshift/)
*
* This is part of [dsp-kit](https://github.com/oramics/dsp-kit)
*
* @example
* var shift = require('dsp-fftshift')
* shift.fftshift(signal)
* shift.ifftshift(signal)
*
* @example
* // ES6 syntax
* import { fftshift, ifftshift } from 'dsp-fftshift'
* fftshift(signal)
*
* @example
* // included in dsp-kit package
* var dsp = require('dsp-kit')
* dsp.fftshift(signal)
* dsp.ifftshift(signal)
*
* @module fftshift
*/
/**
* Rotate a buffer in place
*
* from: http://stackoverflow.com/questions/876293/fastest-algorithm-for-circle-shift-n-sized-array-for-m-position
*
* @param {Array} source - the buffer to rotate
* @param {Number} rotations - the number of rotations
* @private
*/
function rotate (src, n) {
var len = src.length
reverse(src, 0, len)
reverse(src, 0, n)
reverse(src, n, len)
return src
}
function reverse (src, from, to) {
--from
while (++from < --to) {
var tmp = src[from]
src[from] = src[to]
src[to] = tmp
}
}
/**
* Zero-phase windowing alignment
*
* __CAUTION__: this function mutates the array
*
* Perform a cyclic shifting (rotation) to set the first sample at the middle
* of the buffer (it reorder buffer samples from (0:N-1) to [(N/2:N-1) (0:(N/2-1))])
*
* Named by the same function in mathlab: `fftshift`
*
* @param {Array} buffer
* @return {Array} the same buffer (with the data rotated)
*/
export function fftshift (src) {
const len = src.length
return rotate(src, Math.floor(len / 2))
}
/**
* Inverse of zero-phase windowing alignment
*
* __CAUTION__: this function mutates the array
*
* @see fftshift
* @param {Array} buffer
* @return {Array} the same buffer (with the data rotated)
*/
export function ifftshift (src) {
const len = src.length
return rotate(src, Math.floor((len + 1) / 2))
}