Pitch Shift Audio Effect. More...
#include "asterisk.h"#include "asterisk/module.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/utils.h"#include "asterisk/audiohook.h"#include <math.h>
Go to the source code of this file.
Data Structures | |
| struct | fft_data |
| struct | pitchshift_data |
Defines | |
| #define | HIGH 1.25 |
| #define | HIGHER 1.5 |
| #define | HIGHEST 2 |
| #define | LOW .85 |
| #define | LOWER .7 |
| #define | LOWEST .5 |
| #define | M_PI 3.14159265358979323846 |
| #define | MAX_FRAME_LENGTH 256 |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static void | destroy_callback (void *data) |
| static int | load_module (void) |
| static int | pitch_shift (struct ast_frame *f, float amount, struct fft_data *fft_data) |
| static int | pitchshift_cb (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *f, enum ast_audiohook_direction direction) |
| static int | pitchshift_helper (struct ast_channel *chan, const char *cmd, char *data, const char *value) |
| static void | smb_fft (float *fft_buffer, long fft_frame_size, long sign) |
| static void | smb_pitch_shift (float pitchShift, long num_samps_to_process, long fft_frame_size, long osamp, float sample_rate, int16_t *indata, int16_t *outdata, struct fft_data *fft_data) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Audio Effects Dialplan Functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_custom_function | pitch_shift_function |
| static struct ast_datastore_info | pitchshift_datastore |
Pitch Shift Audio Effect.
Definition in file func_pitchshift.c.
| #define HIGH 1.25 |
Definition at line 122 of file func_pitchshift.c.
Referenced by pitchshift_helper().
| #define HIGHER 1.5 |
Definition at line 121 of file func_pitchshift.c.
Referenced by pitchshift_helper().
| #define HIGHEST 2 |
Definition at line 120 of file func_pitchshift.c.
Referenced by pitchshift_helper().
| #define LOW .85 |
Definition at line 123 of file func_pitchshift.c.
Referenced by pitchshift_helper().
| #define LOWER .7 |
Definition at line 124 of file func_pitchshift.c.
Referenced by pitchshift_helper().
| #define LOWEST .5 |
Definition at line 125 of file func_pitchshift.c.
Referenced by pitchshift_helper().
| #define M_PI 3.14159265358979323846 |
Definition at line 116 of file func_pitchshift.c.
Referenced by ast_playtones_start(), callerid_init(), goertzel_init(), make_tone_burst(), smb_fft(), smb_pitch_shift(), tdd_init(), and tonepair_alloc().
| #define MAX_FRAME_LENGTH 256 |
Definition at line 118 of file func_pitchshift.c.
Referenced by pitch_shift().
| static void __reg_module | ( | void | ) | [static] |
Definition at line 510 of file func_pitchshift.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 510 of file func_pitchshift.c.
| static void destroy_callback | ( | void * | data | ) | [static] |
Definition at line 153 of file func_pitchshift.c.
References ast_audiohook_destroy(), ast_free, and pitchshift_data::audiohook.
{
struct pitchshift_data *shift = data;
ast_audiohook_destroy(&shift->audiohook);
ast_free(shift);
};
| static int load_module | ( | void | ) | [static] |
Definition at line 504 of file func_pitchshift.c.
References ast_custom_function_register, AST_MODULE_LOAD_DECLINE, and AST_MODULE_LOAD_SUCCESS.
{
int res = ast_custom_function_register(&pitch_shift_function);
return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
}
Definition at line 478 of file func_pitchshift.c.
References ast_format_rate(), ast_frame_subclass::codec, ast_frame::data, MAX_FRAME_LENGTH, ast_frame::ptr, ast_frame::samples, smb_pitch_shift(), and ast_frame::subclass.
Referenced by pitchshift_cb().
{
int16_t *fun = (int16_t *) f->data.ptr;
int samples;
/* an amount of 1 has no effect */
if (!amount || amount == 1 || !fun || (f->samples % 32)) {
return 0;
}
for (samples = 0; samples < f->samples; samples += 32) {
smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_rate(f->subclass.codec), fun+samples, fun+samples, fft);
}
return 0;
}
| static int pitchshift_cb | ( | struct ast_audiohook * | audiohook, |
| struct ast_channel * | chan, | ||
| struct ast_frame * | f, | ||
| enum ast_audiohook_direction | direction | ||
| ) | [static] |
Definition at line 166 of file func_pitchshift.c.
References AST_AUDIOHOOK_DIRECTION_WRITE, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16, AST_FRAME_VOICE, ast_frame_subclass::codec, ast_datastore::data, ast_frame::frametype, pitch_shift(), pitchshift_data::rx, fft_data::shift_amount, ast_audiohook::status, ast_frame::subclass, and pitchshift_data::tx.
Referenced by pitchshift_helper().
{
struct ast_datastore *datastore = NULL;
struct pitchshift_data *shift = NULL;
if (!f) {
return 0;
}
if ((audiohook->status == AST_AUDIOHOOK_STATUS_DONE) ||
(f->frametype != AST_FRAME_VOICE) ||
((f->subclass.codec != AST_FORMAT_SLINEAR) &&
(f->subclass.codec != AST_FORMAT_SLINEAR16))) {
return -1;
}
if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) {
return -1;
}
shift = datastore->data;
if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) {
pitch_shift(f, shift->tx.shift_amount, &shift->tx);
} else {
pitch_shift(f, shift->rx.shift_amount, &shift->rx);
}
return 0;
}
| static int pitchshift_helper | ( | struct ast_channel * | chan, |
| const char * | cmd, | ||
| char * | data, | ||
| const char * | value | ||
| ) | [static] |
Definition at line 197 of file func_pitchshift.c.
References ast_audiohook_attach(), ast_audiohook_init(), AST_AUDIOHOOK_TYPE_MANIPULATE, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc(), ast_datastore_free(), ast_log(), pitchshift_data::audiohook, ast_datastore::data, HIGH, HIGHER, HIGHEST, LOG_ERROR, LOW, LOWER, LOWEST, ast_audiohook::manipulate_callback, pitchshift_cb(), pitchshift_data::rx, fft_data::shift_amount, and pitchshift_data::tx.
{
struct ast_datastore *datastore = NULL;
struct pitchshift_data *shift = NULL;
int new = 0;
float amount = 0;
ast_channel_lock(chan);
if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) {
ast_channel_unlock(chan);
if (!(datastore = ast_datastore_alloc(&pitchshift_datastore, NULL))) {
return 0;
}
if (!(shift = ast_calloc(1, sizeof(*shift)))) {
ast_datastore_free(datastore);
return 0;
}
ast_audiohook_init(&shift->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "pitch_shift");
shift->audiohook.manipulate_callback = pitchshift_cb;
datastore->data = shift;
new = 1;
} else {
ast_channel_unlock(chan);
shift = datastore->data;
}
if (!strcasecmp(value, "highest")) {
amount = HIGHEST;
} else if (!strcasecmp(value, "higher")) {
amount = HIGHER;
} else if (!strcasecmp(value, "high")) {
amount = HIGH;
} else if (!strcasecmp(value, "lowest")) {
amount = LOWEST;
} else if (!strcasecmp(value, "lower")) {
amount = LOWER;
} else if (!strcasecmp(value, "low")) {
amount = LOW;
} else {
if (!sscanf(value, "%30f", &amount) || (amount <= 0) || (amount > 4)) {
goto cleanup_error;
}
}
if (!strcasecmp(data, "rx")) {
shift->rx.shift_amount = amount;
} else if (!strcasecmp(data, "tx")) {
shift->tx.shift_amount = amount;
} else if (!strcasecmp(data, "both")) {
shift->rx.shift_amount = amount;
shift->tx.shift_amount = amount;
} else {
goto cleanup_error;
}
if (new) {
ast_channel_lock(chan);
ast_channel_datastore_add(chan, datastore);
ast_channel_unlock(chan);
ast_audiohook_attach(chan, &shift->audiohook);
}
return 0;
cleanup_error:
ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
if (new) {
ast_datastore_free(datastore);
}
return -1;
}
| static void smb_fft | ( | float * | fft_buffer, |
| long | fft_frame_size, | ||
| long | sign | ||
| ) | [static] |
Definition at line 273 of file func_pitchshift.c.
Referenced by smb_pitch_shift().
{
float wr, wi, arg, *p1, *p2, temp;
float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
long i, bitm, j, le, le2, k;
for (i = 2; i < 2 * fft_frame_size - 2; i += 2) {
for (bitm = 2, j = 0; bitm < 2 * fft_frame_size; bitm <<= 1) {
if (i & bitm) {
j++;
}
j <<= 1;
}
if (i < j) {
p1 = fft_buffer + i; p2 = fft_buffer + j;
temp = *p1; *(p1++) = *p2;
*(p2++) = temp; temp = *p1;
*p1 = *p2; *p2 = temp;
}
}
for (k = 0, le = 2; k < (long) (log(fft_frame_size) / log(2.) + .5); k++) {
le <<= 1;
le2 = le>>1;
ur = 1.0;
ui = 0.0;
arg = M_PI / (le2>>1);
wr = cos(arg);
wi = sign * sin(arg);
for (j = 0; j < le2; j += 2) {
p1r = fft_buffer+j; p1i = p1r + 1;
p2r = p1r + le2; p2i = p2r + 1;
for (i = j; i < 2 * fft_frame_size; i += le) {
tr = *p2r * ur - *p2i * ui;
ti = *p2r * ui + *p2i * ur;
*p2r = *p1r - tr; *p2i = *p1i - ti;
*p1r += tr; *p1i += ti;
p1r += le; p1i += le;
p2r += le; p2i += le;
}
tr = ur * wr - ui * wi;
ui = ur * wi + ui * wr;
ur = tr;
}
}
}
| static void smb_pitch_shift | ( | float | pitchShift, |
| long | num_samps_to_process, | ||
| long | fft_frame_size, | ||
| long | osamp, | ||
| float | sample_rate, | ||
| int16_t * | indata, | ||
| int16_t * | outdata, | ||
| struct fft_data * | fft_data | ||
| ) | [static] |
Definition at line 319 of file func_pitchshift.c.
References fft_data::ana_freq, fft_data::ana_magn, cos, fft_data::fft_worksp, fft_data::gRover, fft_data::in_fifo, fft_data::last_phase, M_PI, fft_data::out_fifo, fft_data::output_accum, smb_fft(), step_size(), fft_data::sum_phase, fft_data::syn_freq, and fft_data::sys_magn.
Referenced by pitch_shift().
{
float *in_fifo = fft_data->in_fifo;
float *out_fifo = fft_data->out_fifo;
float *fft_worksp = fft_data->fft_worksp;
float *last_phase = fft_data->last_phase;
float *sum_phase = fft_data->sum_phase;
float *output_accum = fft_data->output_accum;
float *ana_freq = fft_data->ana_freq;
float *ana_magn = fft_data->ana_magn;
float *syn_freq = fft_data->syn_freq;
float *sys_magn = fft_data->sys_magn;
double magn, phase, tmp, window, real, imag;
double freq_per_bin, expct;
long i,k, qpd, index, in_fifo_latency, step_size, fft_frame_size2;
/* set up some handy variables */
fft_frame_size2 = fft_frame_size / 2;
step_size = fft_frame_size / osamp;
freq_per_bin = sample_rate / (double) fft_frame_size;
expct = 2. * M_PI * (double) step_size / (double) fft_frame_size;
in_fifo_latency = fft_frame_size-step_size;
if (fft_data->gRover == 0) {
fft_data->gRover = in_fifo_latency;
}
/* main processing loop */
for (i = 0; i < num_samps_to_process; i++){
/* As long as we have not yet collected enough data just read in */
in_fifo[fft_data->gRover] = indata[i];
outdata[i] = out_fifo[fft_data->gRover - in_fifo_latency];
fft_data->gRover++;
/* now we have enough data for processing */
if (fft_data->gRover >= fft_frame_size) {
fft_data->gRover = in_fifo_latency;
/* do windowing and re,im interleave */
for (k = 0; k < fft_frame_size;k++) {
window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
fft_worksp[2*k] = in_fifo[k] * window;
fft_worksp[2*k+1] = 0.;
}
/* ***************** ANALYSIS ******************* */
/* do transform */
smb_fft(fft_worksp, fft_frame_size, -1);
/* this is the analysis step */
for (k = 0; k <= fft_frame_size2; k++) {
/* de-interlace FFT buffer */
real = fft_worksp[2*k];
imag = fft_worksp[2*k+1];
/* compute magnitude and phase */
magn = 2. * sqrt(real * real + imag * imag);
phase = atan2(imag, real);
/* compute phase difference */
tmp = phase - last_phase[k];
last_phase[k] = phase;
/* subtract expected phase difference */
tmp -= (double) k * expct;
/* map delta phase into +/- Pi interval */
qpd = tmp / M_PI;
if (qpd >= 0) {
qpd += qpd & 1;
} else {
qpd -= qpd & 1;
}
tmp -= M_PI * (double) qpd;
/* get deviation from bin frequency from the +/- Pi interval */
tmp = osamp * tmp / (2. * M_PI);
/* compute the k-th partials' true frequency */
tmp = (double) k * freq_per_bin + tmp * freq_per_bin;
/* store magnitude and true frequency in analysis arrays */
ana_magn[k] = magn;
ana_freq[k] = tmp;
}
/* ***************** PROCESSING ******************* */
/* this does the actual pitch shifting */
memset(sys_magn, 0, fft_frame_size * sizeof(float));
memset(syn_freq, 0, fft_frame_size * sizeof(float));
for (k = 0; k <= fft_frame_size2; k++) {
index = k * pitchShift;
if (index <= fft_frame_size2) {
sys_magn[index] += ana_magn[k];
syn_freq[index] = ana_freq[k] * pitchShift;
}
}
/* ***************** SYNTHESIS ******************* */
/* this is the synthesis step */
for (k = 0; k <= fft_frame_size2; k++) {
/* get magnitude and true frequency from synthesis arrays */
magn = sys_magn[k];
tmp = syn_freq[k];
/* subtract bin mid frequency */
tmp -= (double) k * freq_per_bin;
/* get bin deviation from freq deviation */
tmp /= freq_per_bin;
/* take osamp into account */
tmp = 2. * M_PI * tmp / osamp;
/* add the overlap phase advance back in */
tmp += (double) k * expct;
/* accumulate delta phase to get bin phase */
sum_phase[k] += tmp;
phase = sum_phase[k];
/* get real and imag part and re-interleave */
fft_worksp[2*k] = magn * cos(phase);
fft_worksp[2*k+1] = magn * sin(phase);
}
/* zero negative frequencies */
for (k = fft_frame_size + 2; k < 2 * fft_frame_size; k++) {
fft_worksp[k] = 0.;
}
/* do inverse transform */
smb_fft(fft_worksp, fft_frame_size, 1);
/* do windowing and add to output accumulator */
for (k = 0; k < fft_frame_size; k++) {
window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5;
output_accum[k] += 2. * window * fft_worksp[2*k] / (fft_frame_size2 * osamp);
}
for (k = 0; k < step_size; k++) {
out_fifo[k] = output_accum[k];
}
/* shift accumulator */
memmove(output_accum, output_accum+step_size, fft_frame_size * sizeof(float));
/* move input FIFO */
for (k = 0; k < in_fifo_latency; k++) {
in_fifo[k] = in_fifo[k+step_size];
}
}
}
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 499 of file func_pitchshift.c.
References ast_custom_function_unregister().
{
return ast_custom_function_unregister(&pitch_shift_function);
}
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Audio Effects Dialplan Functions" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 510 of file func_pitchshift.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 510 of file func_pitchshift.c.
struct ast_custom_function pitch_shift_function [static] |
{
.name = "PITCH_SHIFT",
.write = pitchshift_helper,
}
Definition at line 494 of file func_pitchshift.c.
struct ast_datastore_info pitchshift_datastore [static] |
{
.type = "pitchshift",
.destroy = destroy_callback
}
Definition at line 161 of file func_pitchshift.c.