#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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 |
Definition in file func_pitchshift.c.
#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 |
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 |
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.
00154 { 00155 struct pitchshift_data *shift = data; 00156 00157 ast_audiohook_destroy(&shift->audiohook); 00158 ast_free(shift); 00159 };
static int load_module | ( | void | ) | [static] |
Definition at line 504 of file func_pitchshift.c.
References ast_custom_function_register, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and pitch_shift_function.
00505 { 00506 int res = ast_custom_function_register(&pitch_shift_function); 00507 return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; 00508 }
Definition at line 478 of file func_pitchshift.c.
References ast_format_rate(), f, MAX_FRAME_LENGTH, and smb_pitch_shift().
Referenced by pitchshift_cb().
00479 { 00480 int16_t *fun = (int16_t *) f->data.ptr; 00481 int samples; 00482 00483 /* an amount of 1 has no effect */ 00484 if (!amount || amount == 1 || !fun || (f->samples % 32)) { 00485 return 0; 00486 } 00487 for (samples = 0; samples < f->samples; samples += 32) { 00488 smb_pitch_shift(amount, 32, MAX_FRAME_LENGTH, 32, ast_format_rate(f->subclass.codec), fun+samples, fun+samples, fft); 00489 } 00490 00491 return 0; 00492 }
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, pitchshift_data::audiohook, ast_datastore::data, f, pitch_shift(), pitchshift_datastore, pitchshift_data::rx, fft_data::shift_amount, ast_audiohook::status, and pitchshift_data::tx.
Referenced by pitchshift_helper().
00167 { 00168 struct ast_datastore *datastore = NULL; 00169 struct pitchshift_data *shift = NULL; 00170 00171 00172 if (!f) { 00173 return 0; 00174 } 00175 if ((audiohook->status == AST_AUDIOHOOK_STATUS_DONE) || 00176 (f->frametype != AST_FRAME_VOICE) || 00177 ((f->subclass.codec != AST_FORMAT_SLINEAR) && 00178 (f->subclass.codec != AST_FORMAT_SLINEAR16))) { 00179 return -1; 00180 } 00181 00182 if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) { 00183 return -1; 00184 } 00185 00186 shift = datastore->data; 00187 00188 if (direction == AST_AUDIOHOOK_DIRECTION_WRITE) { 00189 pitch_shift(f, shift->tx.shift_amount, &shift->tx); 00190 } else { 00191 pitch_shift(f, shift->rx.shift_amount, &shift->rx); 00192 } 00193 00194 return 0; 00195 }
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, pitchshift_cb(), pitchshift_datastore, pitchshift_data::rx, fft_data::shift_amount, and pitchshift_data::tx.
00198 { 00199 struct ast_datastore *datastore = NULL; 00200 struct pitchshift_data *shift = NULL; 00201 int new = 0; 00202 float amount = 0; 00203 00204 ast_channel_lock(chan); 00205 if (!(datastore = ast_channel_datastore_find(chan, &pitchshift_datastore, NULL))) { 00206 ast_channel_unlock(chan); 00207 00208 if (!(datastore = ast_datastore_alloc(&pitchshift_datastore, NULL))) { 00209 return 0; 00210 } 00211 if (!(shift = ast_calloc(1, sizeof(*shift)))) { 00212 ast_datastore_free(datastore); 00213 return 0; 00214 } 00215 00216 ast_audiohook_init(&shift->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "pitch_shift"); 00217 shift->audiohook.manipulate_callback = pitchshift_cb; 00218 datastore->data = shift; 00219 new = 1; 00220 } else { 00221 ast_channel_unlock(chan); 00222 shift = datastore->data; 00223 } 00224 00225 00226 if (!strcasecmp(value, "highest")) { 00227 amount = HIGHEST; 00228 } else if (!strcasecmp(value, "higher")) { 00229 amount = HIGHER; 00230 } else if (!strcasecmp(value, "high")) { 00231 amount = HIGH; 00232 } else if (!strcasecmp(value, "lowest")) { 00233 amount = LOWEST; 00234 } else if (!strcasecmp(value, "lower")) { 00235 amount = LOWER; 00236 } else if (!strcasecmp(value, "low")) { 00237 amount = LOW; 00238 } else { 00239 if (!sscanf(value, "%30f", &amount) || (amount <= 0) || (amount > 4)) { 00240 goto cleanup_error; 00241 } 00242 } 00243 00244 if (!strcasecmp(data, "rx")) { 00245 shift->rx.shift_amount = amount; 00246 } else if (!strcasecmp(data, "tx")) { 00247 shift->tx.shift_amount = amount; 00248 } else if (!strcasecmp(data, "both")) { 00249 shift->rx.shift_amount = amount; 00250 shift->tx.shift_amount = amount; 00251 } else { 00252 goto cleanup_error; 00253 } 00254 00255 if (new) { 00256 ast_channel_lock(chan); 00257 ast_channel_datastore_add(chan, datastore); 00258 ast_channel_unlock(chan); 00259 ast_audiohook_attach(chan, &shift->audiohook); 00260 } 00261 00262 return 0; 00263 00264 cleanup_error: 00265 00266 ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd); 00267 if (new) { 00268 ast_datastore_free(datastore); 00269 } 00270 return -1; 00271 }
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().
00274 { 00275 float wr, wi, arg, *p1, *p2, temp; 00276 float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i; 00277 long i, bitm, j, le, le2, k; 00278 00279 for (i = 2; i < 2 * fft_frame_size - 2; i += 2) { 00280 for (bitm = 2, j = 0; bitm < 2 * fft_frame_size; bitm <<= 1) { 00281 if (i & bitm) { 00282 j++; 00283 } 00284 j <<= 1; 00285 } 00286 if (i < j) { 00287 p1 = fft_buffer + i; p2 = fft_buffer + j; 00288 temp = *p1; *(p1++) = *p2; 00289 *(p2++) = temp; temp = *p1; 00290 *p1 = *p2; *p2 = temp; 00291 } 00292 } 00293 for (k = 0, le = 2; k < (long) (log(fft_frame_size) / log(2.) + .5); k++) { 00294 le <<= 1; 00295 le2 = le>>1; 00296 ur = 1.0; 00297 ui = 0.0; 00298 arg = M_PI / (le2>>1); 00299 wr = cos(arg); 00300 wi = sign * sin(arg); 00301 for (j = 0; j < le2; j += 2) { 00302 p1r = fft_buffer+j; p1i = p1r + 1; 00303 p2r = p1r + le2; p2i = p2r + 1; 00304 for (i = j; i < 2 * fft_frame_size; i += le) { 00305 tr = *p2r * ur - *p2i * ui; 00306 ti = *p2r * ui + *p2i * ur; 00307 *p2r = *p1r - tr; *p2i = *p1i - ti; 00308 *p1r += tr; *p1i += ti; 00309 p1r += le; p1i += le; 00310 p2r += le; p2i += le; 00311 } 00312 tr = ur * wr - ui * wi; 00313 ui = ur * wi + ui * wr; 00314 ur = tr; 00315 } 00316 } 00317 }
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().
00320 { 00321 float *in_fifo = fft_data->in_fifo; 00322 float *out_fifo = fft_data->out_fifo; 00323 float *fft_worksp = fft_data->fft_worksp; 00324 float *last_phase = fft_data->last_phase; 00325 float *sum_phase = fft_data->sum_phase; 00326 float *output_accum = fft_data->output_accum; 00327 float *ana_freq = fft_data->ana_freq; 00328 float *ana_magn = fft_data->ana_magn; 00329 float *syn_freq = fft_data->syn_freq; 00330 float *sys_magn = fft_data->sys_magn; 00331 00332 double magn, phase, tmp, window, real, imag; 00333 double freq_per_bin, expct; 00334 long i,k, qpd, index, in_fifo_latency, step_size, fft_frame_size2; 00335 00336 /* set up some handy variables */ 00337 fft_frame_size2 = fft_frame_size / 2; 00338 step_size = fft_frame_size / osamp; 00339 freq_per_bin = sample_rate / (double) fft_frame_size; 00340 expct = 2. * M_PI * (double) step_size / (double) fft_frame_size; 00341 in_fifo_latency = fft_frame_size-step_size; 00342 00343 if (fft_data->gRover == 0) { 00344 fft_data->gRover = in_fifo_latency; 00345 } 00346 00347 /* main processing loop */ 00348 for (i = 0; i < num_samps_to_process; i++){ 00349 00350 /* As long as we have not yet collected enough data just read in */ 00351 in_fifo[fft_data->gRover] = indata[i]; 00352 outdata[i] = out_fifo[fft_data->gRover - in_fifo_latency]; 00353 fft_data->gRover++; 00354 00355 /* now we have enough data for processing */ 00356 if (fft_data->gRover >= fft_frame_size) { 00357 fft_data->gRover = in_fifo_latency; 00358 00359 /* do windowing and re,im interleave */ 00360 for (k = 0; k < fft_frame_size;k++) { 00361 window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5; 00362 fft_worksp[2*k] = in_fifo[k] * window; 00363 fft_worksp[2*k+1] = 0.; 00364 } 00365 00366 /* ***************** ANALYSIS ******************* */ 00367 /* do transform */ 00368 smb_fft(fft_worksp, fft_frame_size, -1); 00369 00370 /* this is the analysis step */ 00371 for (k = 0; k <= fft_frame_size2; k++) { 00372 00373 /* de-interlace FFT buffer */ 00374 real = fft_worksp[2*k]; 00375 imag = fft_worksp[2*k+1]; 00376 00377 /* compute magnitude and phase */ 00378 magn = 2. * sqrt(real * real + imag * imag); 00379 phase = atan2(imag, real); 00380 00381 /* compute phase difference */ 00382 tmp = phase - last_phase[k]; 00383 last_phase[k] = phase; 00384 00385 /* subtract expected phase difference */ 00386 tmp -= (double) k * expct; 00387 00388 /* map delta phase into +/- Pi interval */ 00389 qpd = tmp / M_PI; 00390 if (qpd >= 0) { 00391 qpd += qpd & 1; 00392 } else { 00393 qpd -= qpd & 1; 00394 } 00395 tmp -= M_PI * (double) qpd; 00396 00397 /* get deviation from bin frequency from the +/- Pi interval */ 00398 tmp = osamp * tmp / (2. * M_PI); 00399 00400 /* compute the k-th partials' true frequency */ 00401 tmp = (double) k * freq_per_bin + tmp * freq_per_bin; 00402 00403 /* store magnitude and true frequency in analysis arrays */ 00404 ana_magn[k] = magn; 00405 ana_freq[k] = tmp; 00406 00407 } 00408 00409 /* ***************** PROCESSING ******************* */ 00410 /* this does the actual pitch shifting */ 00411 memset(sys_magn, 0, fft_frame_size * sizeof(float)); 00412 memset(syn_freq, 0, fft_frame_size * sizeof(float)); 00413 for (k = 0; k <= fft_frame_size2; k++) { 00414 index = k * pitchShift; 00415 if (index <= fft_frame_size2) { 00416 sys_magn[index] += ana_magn[k]; 00417 syn_freq[index] = ana_freq[k] * pitchShift; 00418 } 00419 } 00420 00421 /* ***************** SYNTHESIS ******************* */ 00422 /* this is the synthesis step */ 00423 for (k = 0; k <= fft_frame_size2; k++) { 00424 00425 /* get magnitude and true frequency from synthesis arrays */ 00426 magn = sys_magn[k]; 00427 tmp = syn_freq[k]; 00428 00429 /* subtract bin mid frequency */ 00430 tmp -= (double) k * freq_per_bin; 00431 00432 /* get bin deviation from freq deviation */ 00433 tmp /= freq_per_bin; 00434 00435 /* take osamp into account */ 00436 tmp = 2. * M_PI * tmp / osamp; 00437 00438 /* add the overlap phase advance back in */ 00439 tmp += (double) k * expct; 00440 00441 /* accumulate delta phase to get bin phase */ 00442 sum_phase[k] += tmp; 00443 phase = sum_phase[k]; 00444 00445 /* get real and imag part and re-interleave */ 00446 fft_worksp[2*k] = magn * cos(phase); 00447 fft_worksp[2*k+1] = magn * sin(phase); 00448 } 00449 00450 /* zero negative frequencies */ 00451 for (k = fft_frame_size + 2; k < 2 * fft_frame_size; k++) { 00452 fft_worksp[k] = 0.; 00453 } 00454 00455 /* do inverse transform */ 00456 smb_fft(fft_worksp, fft_frame_size, 1); 00457 00458 /* do windowing and add to output accumulator */ 00459 for (k = 0; k < fft_frame_size; k++) { 00460 window = -.5 * cos(2. * M_PI * (double) k / (double) fft_frame_size) + .5; 00461 output_accum[k] += 2. * window * fft_worksp[2*k] / (fft_frame_size2 * osamp); 00462 } 00463 for (k = 0; k < step_size; k++) { 00464 out_fifo[k] = output_accum[k]; 00465 } 00466 00467 /* shift accumulator */ 00468 memmove(output_accum, output_accum+step_size, fft_frame_size * sizeof(float)); 00469 00470 /* move input FIFO */ 00471 for (k = 0; k < in_fifo_latency; k++) { 00472 in_fifo[k] = in_fifo[k+step_size]; 00473 } 00474 } 00475 } 00476 }
static int unload_module | ( | void | ) | [static] |
Definition at line 499 of file func_pitchshift.c.
References ast_custom_function_unregister(), and pitch_shift_function.
00500 { 00501 return ast_custom_function_unregister(&pitch_shift_function); 00502 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .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] |
Initial value:
{ .name = "PITCH_SHIFT", .write = pitchshift_helper, }
Definition at line 494 of file func_pitchshift.c.
Referenced by load_module(), and unload_module().
struct ast_datastore_info pitchshift_datastore [static] |
Initial value:
{ .type = "pitchshift", .destroy = destroy_callback }
Definition at line 161 of file func_pitchshift.c.
Referenced by pitchshift_cb(), and pitchshift_helper().