<commit_before>/*
 * Rational ratio resampler 
 * 
 * Copyright 2012  <NAME> <<EMAIL>>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * See the COPYING file in the main directory for details.
 */

#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include <cstdio>

#include "Logger.h"
#include "Resampler.h"

#define MAX_OUTPUT_LEN		4096

bool Resampler::initFilters()
{
	int i, n;
	int protoLen = mP * mFiltLen;

	float *proto;
	float sum = 0.0f;
	float scale = 0.0f;
	float midpt = protoLen / 2;

	/* 
	 * Allocate partition filters and the temporary prototype filter
	 * according to numerator of the rational rate. Coefficients are
	 * real only and must be 16-byte memory aligned for SSE usage.
	 */
	int flags = CXVEC_FLG_REAL_ONLY | CXVEC_FLG_MEM_ALIGN;

	proto = (float *) malloc(protoLen * sizeof(float));
	if (!proto)
		return false;

	partitions = (struct cxvec **) malloc(sizeof(struct cxvec *) * mP);
	if (!partitions)
		return false;

	for (i = 0; i < mP; i++)
		partitions[i] = cxvec_alloc(mFiltLen, 0, NULL, flags);

	/* 
	 * Generate the prototype filter with a Blackman-harris window.
	 * Scale coefficients with DC filter gain set to unity divided
	 * by the number of filter partitions. 
	 */
	float a0 = 0.35875;
	float a1 = 0.48829;
	float a2 = 0.14128;
	float a3 = 0.01168;

	for (i = 0; i < protoLen; i++) {
		proto[i] = cxvec_sinc(((float) i - midpt) / mP);
		proto[i] *= a0 -
			    a1 * cos(2 * M_PI * i / (protoLen - 1)) +
			    a2 * cos(4 * M_PI * i / (protoLen - 1)) -
			    a3 * cos(6 * M_PI * i / (protoLen - 1));
		sum += proto[i];
	}
	scale = mP / sum;

	/* 
	 * Populate partition filters and reverse the coefficients per
	 * convolution requirements.
	 */
	for (i = 0; i < mFiltLen; i++) {
		for (n = 0; n < mP; n++) {
			partitions[n]->data[i].real = proto[i * mP + n] * scale;
			partitions[n]->data[i].imag = 0.0f;
		}
	}

	for (i = 0; i < mP; i++) {
		cxvec_rvrs(partitions[i], partitions[i]);
	}

	free(proto);

	return true;
}

void Resampler::releaseFilters()
{
	int i;

	for (i = 0; i < mP; i++) {
		cxvec_free(partitions[i]);
	}

	free(partitions);
}

static bool check_vec_len(struct cxvec *in,
			 struct cxvec *out,
			 int p, int q)
{
	if (in->len % q) {
		LOG(ERR) << "Invalid input length " << in->len
			 <<  " is not multiple of " << q;
		return false;
	}

	if (out->len % p) {
		LOG(ERR) << "Invalid output length " << out->len
			 <<  " is not multiple of " << p;
		return false;
	}

	if ((in->len / q) != (out->len / p)) {
		LOG(ERR) << "Input/output block length mismatch";
		return false;
	}

	if (out->len > MAX_OUTPUT_LEN) {
		LOG(ERR) << "Block length of " << out->len << " exceeds max";
		return false;
	}

	return true;
}

void Resampler::computePath()
{
	int i;

	for (i = 0; i < MAX_OUTPUT_LEN; i++) {
		inputIndex[i] = (mQ * i) / mP;
		outputPath[i] = (mQ * i) % mP;
	}
}

int Resampler::rotateSingle(struct cxvec *in, struct cxvec *out, struct cxvec *hist)
{
	int i, n, path;

	if (!check_vec_len(in, out, mP, mQ))
		return -1; 

	/* Insert history */
	memcpy(in->buf, hist->data, hist->len * sizeof(cmplx));

	/* Generate output from precomputed input/output paths */
	for (i = 0; i < out->len; i++) {
		n = inputIndex[i]; 
		path = outputPath[i]; 

		single_convolve(&in->data[n],
				partitions[path],
				&out->data[i]);
	}

	/* Save history */
	memcpy(hist->data, &in->data[in->len - hist->len],
	       hist->len * sizeof(cmplx));

	return out->len;
}

int Resampler::rotate(struct cxvec **in, struct cxvec **out)
{
	int i, len;

	for (i = 0; i < mChanM; i++) {
		if (chanActive[i]) {
			len = rotateSingle(in[i], out[i], history[i]);
		}
	}

	return len;
}

bool Resampler::activateChan(int num)
{
	if ((num >= mChanM) || (num < 0)) {<commit_msg>transceiver: mcbts: explicitly handle inactive channels in resampler<commit_after>/*
 * Rational ratio resampler 
 * 
 * Copyright 2012  <NAME> <<EMAIL>>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * See the COPYING file in the main directory for details.
 */

#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include <cstdio>

#include "Logger.h"
#include "Resampler.h"

#define MAX_OUTPUT_LEN		4096

bool Resampler::initFilters()
{
	int i, n;
	int protoLen = mP * mFiltLen;

	float *proto;
	float sum = 0.0f;
	float scale = 0.0f;
	float midpt = protoLen / 2;

	/* 
	 * Allocate partition filters and the temporary prototype filter
	 * according to numerator of the rational rate. Coefficients are
	 * real only and must be 16-byte memory aligned for SSE usage.
	 */
	int flags = CXVEC_FLG_REAL_ONLY | CXVEC_FLG_MEM_ALIGN;

	proto = (float *) malloc(protoLen * sizeof(float));
	if (!proto)
		return false;

	partitions = (struct cxvec **) malloc(sizeof(struct cxvec *) * mP);
	if (!partitions)
		return false;

	for (i = 0; i < mP; i++)
		partitions[i] = cxvec_alloc(mFiltLen, 0, NULL, flags);

	/* 
	 * Generate the prototype filter with a Blackman-harris window.
	 * Scale coefficients with DC filter gain set to unity divided
	 * by the number of filter partitions. 
	 */
	float a0 = 0.35875;
	float a1 = 0.48829;
	float a2 = 0.14128;
	float a3 = 0.01168;

	for (i = 0; i < protoLen; i++) {
		proto[i] = cxvec_sinc(((float) i - midpt) / mP);
		proto[i] *= a0 -
			    a1 * cos(2 * M_PI * i / (protoLen - 1)) +
			    a2 * cos(4 * M_PI * i / (protoLen - 1)) -
			    a3 * cos(6 * M_PI * i / (protoLen - 1));
		sum += proto[i];
	}
	scale = mP / sum;

	/* 
	 * Populate partition filters and reverse the coefficients per
	 * convolution requirements.
	 */
	for (i = 0; i < mFiltLen; i++) {
		for (n = 0; n < mP; n++) {
			partitions[n]->data[i].real = proto[i * mP + n] * scale;
			partitions[n]->data[i].imag = 0.0f;
		}
	}

	for (i = 0; i < mP; i++) {
		cxvec_rvrs(partitions[i], partitions[i]);
	}

	free(proto);

	return true;
}

void Resampler::releaseFilters()
{
	int i;

	for (i = 0; i < mP; i++) {
		cxvec_free(partitions[i]);
	}

	free(partitions);
}

static bool check_vec_len(struct cxvec *in,
			 struct cxvec *out,
			 int p, int q)
{
	if (in->len % q) {
		LOG(ERR) << "Invalid input length " << in->len
			 <<  " is not multiple of " << q;
		return false;
	}

	if (out->len % p) {
		LOG(ERR) << "Invalid output length " << out->len
			 <<  " is not multiple of " << p;
		return false;
	}

	if ((in->len / q) != (out->len / p)) {
		LOG(ERR) << "Input/output block length mismatch";
		return false;
	}

	if (out->len > MAX_OUTPUT_LEN) {
		LOG(ERR) << "Block length of " << out->len << " exceeds max";
		return false;
	}

	return true;
}

void Resampler::computePath()
{
	int i;

	for (i = 0; i < MAX_OUTPUT_LEN; i++) {
		inputIndex[i] = (mQ * i) / mP;
		outputPath[i] = (mQ * i) % mP;
	}
}

int Resampler::rotateSingle(struct cxvec *in, struct cxvec *out, struct cxvec *hist)
{
	int i, n, path;

	if (!check_vec_len(in, out, mP, mQ))
		return -1; 

	/* Insert history */
	memcpy(in->buf, hist->data, hist->len * sizeof(cmplx));

	/* Generate output from precomputed input/output paths */
	for (i = 0; i < out->len; i++) {
		n = inputIndex[i]; 
		path = outputPath[i]; 

		single_convolve(&in->data[n],
				partitions[path],
				&out->data[i]);
	}

	/* Save history */
	memcpy(hist->data, &in->data[in->len - hist->len],
	       hist->len * sizeof(cmplx));

	return out->len;
}

int Resampler::rotate(struct cxvec **in, struct cxvec **out)
{
	int len = 0;

	for (int i = 0; i < mChanM; i++) {
		if (chanActive[i])
			len = rotateSingle(in[i], out[i], history[i]);
		else
			cxvec_reset(out[i]);
	}

	return len;
}

bool Resampler::activateChan(int num)
{
	if ((num >= mChanM) || (num < 0)) {
{'fraction_non_alphanumeric': 0.15042444821731749, 'fraction_numerical': 0.015506508205998868, 'mean_word_length': 3.1581176470588237, 'pattern_counts': {'":': 0, '<': 89, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6172895', 'n_tokens_mistral': 3550, 'n_tokens_neox': 3217, 'n_words': 1042}